created new crate
7
FCLauncher.old/src-tauri/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Generated by Tauri
|
||||
# will have schema files for capabilities auto-completion
|
||||
/gen/schemas
|
39
FCLauncher.old/src-tauri/Cargo.toml
Normal file
@ -0,0 +1,39 @@
|
||||
[package]
|
||||
name = "fclauncher"
|
||||
version = "0.0.5"
|
||||
description = "Launcher for Familycraft"
|
||||
authors = ["Samuel Walker", "Benjamin Walker"]
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "2", features = [] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
suppaftp = { version = "6.0.1", features = ["native-tls"] }
|
||||
tar = "0.4.41"
|
||||
flate2 = "1.0.30"
|
||||
zip-extract = "0.1.3"
|
||||
dirs = "5.0.1"
|
||||
gethostname = "0.4.3"
|
||||
self_update = "0.40.0"
|
||||
parking_lot = "0.12.3"
|
||||
reqwest = { version = "0.12.5", features = ["stream"] }
|
||||
futures-util = "0.3.30"
|
||||
ssh2 = "0.9.4"
|
||||
chrono = "0.4.38"
|
||||
zip = "2.1.3"
|
||||
tauri-plugin-dialog = "2"
|
||||
tauri-plugin-shell = "2"
|
||||
tauri-plugin-process = "2"
|
||||
|
||||
[features]
|
||||
# This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!!
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||
tauri-plugin-updater = "2"
|
3
FCLauncher.old/src-tauri/build.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
4
FCLauncher.old/src-tauri/build.sh
Executable file
@ -0,0 +1,4 @@
|
||||
export TAURI_PRIVATE_KEY=$(cat ~/.tauri/fclauncher.key)
|
||||
read -s PASSWORD
|
||||
export TAURI_KEY_PASSWORD=$PASSWORD
|
||||
NO_STRIP=true cargo tauri build
|
11
FCLauncher.old/src-tauri/capabilities/desktop.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"identifier": "desktop-capability",
|
||||
"platforms": [
|
||||
"macOS",
|
||||
"windows",
|
||||
"linux"
|
||||
],
|
||||
"permissions": [
|
||||
"updater:default"
|
||||
]
|
||||
}
|
20
FCLauncher.old/src-tauri/capabilities/migrated.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"identifier": "migrated",
|
||||
"description": "permissions that were migrated from v1",
|
||||
"local": true,
|
||||
"windows": [
|
||||
"main"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"shell:allow-open",
|
||||
"dialog:allow-open",
|
||||
"dialog:allow-message",
|
||||
"dialog:allow-ask",
|
||||
"process:allow-restart",
|
||||
"process:allow-exit",
|
||||
"dialog:default",
|
||||
"shell:default",
|
||||
"process:default"
|
||||
]
|
||||
}
|
BIN
FCLauncher.old/src-tauri/icons/128x128.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
FCLauncher.old/src-tauri/icons/128x128@2x.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
FCLauncher.old/src-tauri/icons/32x32.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
FCLauncher.old/src-tauri/icons/Square107x107Logo.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
FCLauncher.old/src-tauri/icons/Square142x142Logo.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
FCLauncher.old/src-tauri/icons/Square150x150Logo.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
FCLauncher.old/src-tauri/icons/Square284x284Logo.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
FCLauncher.old/src-tauri/icons/Square30x30Logo.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
FCLauncher.old/src-tauri/icons/Square310x310Logo.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
FCLauncher.old/src-tauri/icons/Square44x44Logo.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
FCLauncher.old/src-tauri/icons/Square71x71Logo.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
FCLauncher.old/src-tauri/icons/Square89x89Logo.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
FCLauncher.old/src-tauri/icons/StoreLogo.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
FCLauncher.old/src-tauri/icons/icon.icns
Normal file
BIN
FCLauncher.old/src-tauri/icons/icon.ico
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
FCLauncher.old/src-tauri/icons/icon.png
Normal file
After Width: | Height: | Size: 53 KiB |
24
FCLauncher.old/src-tauri/res/vsftpd.crt
Normal file
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID8TCCAtmgAwIBAgIUeFYZmMrAiIFZ9/QFwUS636XZrJMwDQYJKoZIhvcNAQEL
|
||||
BQAwgYcxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdXeW9taW5nMREwDwYDVQQHDAhD
|
||||
aGV5ZW5uZTERMA8GA1UECgwIUGVyc29uYWwxGzAZBgNVBAMMEmdpdGVhLnBpd2Fs
|
||||
a2VyLm5ldDEjMCEGCSqGSIb3DQEJARYUc3dhbGtlckBwaXdhbGtlci5uZXQwHhcN
|
||||
MjQwNjIyMDAzNzEwWhcNMjUwNjIyMDAzNzEwWjCBhzELMAkGA1UEBhMCVVMxEDAO
|
||||
BgNVBAgMB1d5b21pbmcxETAPBgNVBAcMCENoZXllbm5lMREwDwYDVQQKDAhQZXJz
|
||||
b25hbDEbMBkGA1UEAwwSZ2l0ZWEucGl3YWxrZXIubmV0MSMwIQYJKoZIhvcNAQkB
|
||||
FhRzd2Fsa2VyQHBpd2Fsa2VyLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBANOo7BOAUKhbBWodZqY8U34sQhK5Zj6WkVPQrFG1MWXX3KarDtBSuZ99
|
||||
PjbIoDR+Xm5MuNcJMnbeG4+EH6SrNsogHoyn7m8XJAQ/1N6kHEii4qeDzMIbcNu6
|
||||
7L54ZbONBw1Sygilnavp1iPY/2GzWH5ynaT4w4hQQrmDm8GlDNjxWGnw1CpOExAs
|
||||
LdUP3sF6RNtN6dX1vgYMo9ziNtRazRmDANXykgrfBrPCyjUGDsI9wnqm21qoaQ/s
|
||||
w506XovYI1Q6zWVu6cWUYyCFy4mABQxOOf7doJi4h6Wbxfp4WbNdcoBDHDN4nHzo
|
||||
pdrMzJ8GlZD0aCmmU+8ERvIk+IXY6+kCAwEAAaNTMFEwHQYDVR0OBBYEFJ/4/N4x
|
||||
fO/5nu/snApQO7Cw6CyCMB8GA1UdIwQYMBaAFJ/4/N4xfO/5nu/snApQO7Cw6CyC
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAMFwno+imd5ApXP4
|
||||
NsuX6db5GLiT6SHV65iactFUbnvqvK35KQMKVW03hOb2FPwAzEPARcPtFlENAWBl
|
||||
mHphDwAmfLbHXHdiTAKJNFO7D/AOB4TG6geBFlhYvwHCVS17nzFRJvF/0APlgbO8
|
||||
8f3XkmPBPudaGiuKHWdppdHCisk6CfYvNNnjguxihyUL/mDkwiKYQPcHsMYwdYM0
|
||||
QWCcTNyCjnFK/pbo6dLyPAFpXE9becSEhbxvFziNelADRflLkOUSd+sfxmoLMMsA
|
||||
EJajfocYQkAOiuh8uVzol9xsnKcZiujRoTSnndZsRVqfiNZaJbpvZoD/kY0aBXHo
|
||||
SIh5Ff4=
|
||||
-----END CERTIFICATE-----
|
47
FCLauncher.old/src-tauri/src/2
Normal file
@ -0,0 +1,47 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::{io::Cursor, path::PathBuf};
|
||||
use std::io::Seek;
|
||||
use serde_json::{Map, Result, Value};
|
||||
|
||||
mod ftp;
|
||||
mod java;
|
||||
mod prism;
|
||||
mod system_dirs;
|
||||
mod util;
|
||||
mod modpack;
|
||||
|
||||
struct ModpackEntry{
|
||||
name: String,
|
||||
id: u8
|
||||
}
|
||||
|
||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn get_modpacks() -> Vec<ModpackEntry> {
|
||||
let mut buf = Cursor::new(vec![]);
|
||||
ftp::ftp_retr(PathBuf::new().join("modpacks.json"), &mut buf, |_| return);
|
||||
buf.rewind();
|
||||
let v: Value = serde_json::from_reader(buf).unwrap();
|
||||
println!("{}", v[0]["name"]);
|
||||
let mut packs: Vec<ModpackEntry> = Vec::new();
|
||||
for pack in v.as_array().unwrap() {
|
||||
packs.push(ModpackEntry{name: pack["name"].as_str().unwrap().to_string(), id: pack["id"].into()});
|
||||
}
|
||||
return packs;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
prism::install_prism();
|
||||
tauri::Builder::default()
|
||||
.invoke_handler(tauri::generate_handler![greet, get_modpacks])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
295
FCLauncher.old/src-tauri/src/admin.rs
Normal file
@ -0,0 +1,295 @@
|
||||
use std::fs::File;
|
||||
use std::io::Cursor;
|
||||
use std::io::Read;
|
||||
use std::io::Seek;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::modpack;
|
||||
use crate::modpack::get_modpacks;
|
||||
use crate::modpack::get_versions;
|
||||
use crate::modpack::VersionEntry;
|
||||
use crate::sftp;
|
||||
use chrono;
|
||||
use serde::Serialize;
|
||||
use ssh2::Session;
|
||||
use zip::write::SimpleFileOptions;
|
||||
use zip::ZipArchive;
|
||||
use zip::ZipWriter;
|
||||
use tauri::Emitter;
|
||||
|
||||
//static USERNAME: parking_lot::Mutex<String> = parking_lot::const_mutex(String::new());
|
||||
//static PASSWORD: parking_lot::Mutex<String> = parking_lot::const_mutex(String::new());
|
||||
static SESSION: tauri::async_runtime::Mutex<Option<Session>> =
|
||||
tauri::async_runtime::Mutex::const_new(None);
|
||||
|
||||
pub fn emit(event: &str, payload: impl Serialize + Clone, window: tauri::AppHandle) {
|
||||
if !window.emit(event, payload).is_ok() {
|
||||
println!("Failed to emit to window!");
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn login(username: String, password: String, window: tauri::AppHandle) {
|
||||
let res = sftp::connect(username, password);
|
||||
if res.is_ok() {
|
||||
//*USERNAME.lock() = username;
|
||||
//*PASSWORD.lock() = password;
|
||||
*SESSION.lock().await = Some(res.unwrap());
|
||||
emit("Login_Success", {}, window);
|
||||
} else {
|
||||
emit("Login_Failed", {}, window);
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn drop_session() {
|
||||
let ref mut session = *SESSION.lock().await;
|
||||
if let Some(session) = session {
|
||||
session.disconnect(None, "disconnecting", None).unwrap();
|
||||
}
|
||||
*session = None;
|
||||
}
|
||||
|
||||
async fn update_modpacks(modpacks: Vec<modpack::ModpackEntry>) -> Result<(), String> {
|
||||
let data = serde_json::to_string(&modpacks).or(Err("Unable to serialize json"))?;
|
||||
let reader = Cursor::new(data.as_bytes());
|
||||
let ref mut session = *SESSION.lock().await;
|
||||
if let Some(session) = session {
|
||||
sftp::uplaod(
|
||||
None,
|
||||
session.clone(),
|
||||
PathBuf::from("/ftp/modpacks.json"),
|
||||
reader,
|
||||
format!("modpacks.json"),
|
||||
data.as_bytes().len(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Err(format!("Session doesnt exist?"))
|
||||
}
|
||||
|
||||
async fn update_versions(id: String, versions: Vec<modpack::VersionEntry>) -> Result<(), String> {
|
||||
let data = serde_json::to_string(&versions).or(Err("Unable to serialize json"))?;
|
||||
let reader = Cursor::new(data.as_bytes());
|
||||
let ref mut session = *SESSION.lock().await;
|
||||
if let Some(session) = session {
|
||||
sftp::uplaod(
|
||||
None,
|
||||
session.clone(),
|
||||
PathBuf::from(format!("/ftp/{}/versions.json", id)),
|
||||
reader,
|
||||
format!("modpacks.json"),
|
||||
data.as_bytes().len(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Err(format!("Session doesnt exist?"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn shift_up(id: String, window: tauri::AppHandle) {
|
||||
let mut modpacks = modpack::get_modpacks().await;
|
||||
let mut index = 0;
|
||||
for pack in modpacks.as_slice() {
|
||||
if pack.id == id {
|
||||
break;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
if index != 0 {
|
||||
modpacks.swap(index, index - 1);
|
||||
}
|
||||
let res = update_modpacks(modpacks).await;
|
||||
if !res.is_ok() {
|
||||
emit("Error", res.unwrap_err(), window);
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn shift_down(id: String, window: tauri::AppHandle) {
|
||||
let mut modpacks = modpack::get_modpacks().await;
|
||||
let mut index = 0;
|
||||
for pack in modpacks.as_slice() {
|
||||
if pack.id == id {
|
||||
break;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
if index != modpacks.len() - 1 {
|
||||
modpacks.swap(index, index + 1);
|
||||
}
|
||||
let res = update_modpacks(modpacks).await;
|
||||
if !res.is_ok() {
|
||||
emit("Error", res.unwrap_err(), window);
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn add_pack(id: String, name: String, window: tauri::AppHandle) {
|
||||
{
|
||||
let ref mut session = *SESSION.lock().await;
|
||||
if let Some(session) = session {
|
||||
let res = sftp::mkdir(session.clone(), PathBuf::from(format!("/ftp/{}", id))).await;
|
||||
if !res.is_ok() {
|
||||
emit("Error", res.unwrap_err(), window.clone());
|
||||
}
|
||||
let res = sftp::mkdir(
|
||||
session.clone(),
|
||||
PathBuf::from(format!("/ftp/{}/Versions", id)),
|
||||
)
|
||||
.await;
|
||||
if !res.is_ok() {
|
||||
emit("Error", res.unwrap_err(), window.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
let versions: Vec<VersionEntry> = Vec::new();
|
||||
let res = update_versions(id.clone(), versions).await;
|
||||
if !res.is_ok() {
|
||||
emit("Error", res.unwrap_err(), window.clone());
|
||||
}
|
||||
let mut modpacks = get_modpacks().await;
|
||||
modpacks.push(modpack::ModpackEntry {
|
||||
id: id,
|
||||
name: name,
|
||||
last_updated: format!("{:?}", chrono::offset::Utc::now()),
|
||||
});
|
||||
let res = update_modpacks(modpacks).await;
|
||||
if !res.is_ok() {
|
||||
emit("Error", res.unwrap_err(), window);
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn remove_pack(id: String, window: tauri::AppHandle) {
|
||||
let mut modpacks = get_modpacks().await;
|
||||
let mut index = 0;
|
||||
for pack in modpacks.clone() {
|
||||
if pack.id == id {
|
||||
modpacks.remove(index);
|
||||
break;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
let res = update_modpacks(modpacks).await;
|
||||
if !res.is_ok() {
|
||||
emit("Error", res.unwrap_err(), window);
|
||||
}
|
||||
{
|
||||
let ref mut session = *SESSION.lock().await;
|
||||
if let Some(session) = session {
|
||||
sftp::rmdir(session.clone(), PathBuf::from(format!("/ftp/{}", id))).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn update_pack(
|
||||
window: tauri::AppHandle,
|
||||
id: String,
|
||||
path: String,
|
||||
version: String,
|
||||
) -> Result<(), String> {
|
||||
println!(
|
||||
"Update modpack {}, to version {}, from file {}",
|
||||
id, version, path
|
||||
);
|
||||
let file = File::open(Path::new(path.as_str())).or(Err(format!("Unable to open file")))?;
|
||||
let mut archive = ZipArchive::new(file).or(Err(format!("File not a zip archive!")))?;
|
||||
let mut buf = Cursor::new(vec![]);
|
||||
let mut out_archive = ZipWriter::new(&mut buf);
|
||||
|
||||
for i in 0..archive.len() {
|
||||
let mut file = archive
|
||||
.by_index(i)
|
||||
.or(Err(format!("error reading archive")))?;
|
||||
if file.name() == "overrides/version.txt" {
|
||||
continue;
|
||||
}
|
||||
let res = out_archive.start_file(
|
||||
file.name(),
|
||||
SimpleFileOptions::default().compression_method(zip::CompressionMethod::Deflated),
|
||||
);
|
||||
if !res.is_ok() {
|
||||
emit("Error", format!("Unable to start zip archive"), window);
|
||||
return Err(format!("Unable to start zip archive"));
|
||||
}
|
||||
let res = std::io::copy(&mut file, &mut out_archive);
|
||||
if !res.is_ok() {
|
||||
emit("Error", format!("Unable to copy archive to ram"), window);
|
||||
return Err(format!("Unable to copy archive to ram"));
|
||||
}
|
||||
}
|
||||
let res = out_archive.start_file(
|
||||
"overrides/version.txt",
|
||||
SimpleFileOptions::default().compression_method(zip::CompressionMethod::Deflated),
|
||||
);
|
||||
if !res.is_ok() {
|
||||
emit("Error", format!("Unable to create version file"), window);
|
||||
return Err(format!("Unable to create version file"));
|
||||
}
|
||||
let res = out_archive.write_all(version.as_bytes());
|
||||
if !res.is_ok() {
|
||||
emit("Error", format!("Unable to write to zip"), window);
|
||||
return Err(format!("Unable to write to zip"));
|
||||
}
|
||||
let res = out_archive.finish();
|
||||
if !res.is_ok() {
|
||||
emit("Error", format!("Unable to finish zip"), window);
|
||||
return Err(format!("Unable to finish zip"));
|
||||
}
|
||||
buf.rewind().unwrap();
|
||||
let timestamp = format!("{:?}", chrono::offset::Utc::now());
|
||||
let path = format!("Versions/{}-{}.mrpack", id, timestamp);
|
||||
{
|
||||
let ref mut session = *SESSION.lock().await;
|
||||
if let Some(session) = session {
|
||||
let size = buf.clone().bytes().count();
|
||||
let upload_path = format!("/ftp/{}/{}", id, path.clone());
|
||||
println!("Uploading to {}", upload_path);
|
||||
let res = sftp::uplaod(
|
||||
Some(window.clone()),
|
||||
session.clone(),
|
||||
PathBuf::from(upload_path),
|
||||
&mut buf,
|
||||
path.clone(),
|
||||
size,
|
||||
)
|
||||
.await;
|
||||
if !res.is_ok() {
|
||||
emit("Error", res.clone().unwrap_err(), window.clone());
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut versions = get_versions(id.clone()).await?;
|
||||
versions.push(VersionEntry {
|
||||
Version: version,
|
||||
Date: timestamp.clone(),
|
||||
File: path,
|
||||
});
|
||||
let res = update_versions(id.clone(), versions).await;
|
||||
if !res.is_ok() {
|
||||
emit("Error", res.clone().unwrap_err(), window.clone());
|
||||
return res;
|
||||
}
|
||||
let mut modpacks = get_modpacks().await;
|
||||
let mut index = 0;
|
||||
for pack in modpacks.as_slice() {
|
||||
if pack.id == id {
|
||||
modpacks[index].last_updated = timestamp;
|
||||
break;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
let res = update_modpacks(modpacks).await;
|
||||
if !res.is_ok() {
|
||||
emit("Error", res.clone().unwrap_err(), window.clone());
|
||||
return res;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
62
FCLauncher.old/src-tauri/src/ftp.rs
Normal file
@ -0,0 +1,62 @@
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use suppaftp::FtpError;
|
||||
use suppaftp::NativeTlsFtpStream;
|
||||
use suppaftp::NativeTlsConnector;
|
||||
use suppaftp::native_tls::Certificate;
|
||||
use suppaftp::native_tls::TlsConnector;
|
||||
|
||||
|
||||
fn ftp_connection_anonymous() -> Result<NativeTlsFtpStream, FtpError>{
|
||||
ftp_connection("anonymous", "anonymous@")
|
||||
}
|
||||
|
||||
pub fn test_cred(username: &str, password: &str) -> bool{
|
||||
return ftp_connection(username, password).is_ok();
|
||||
}
|
||||
|
||||
|
||||
fn ftp_connection(username: &str, password: &str) -> Result<NativeTlsFtpStream, FtpError>{
|
||||
let ftp_stream = NativeTlsFtpStream::connect("gitea.piwalker.net:21")?;
|
||||
let cert = include_bytes!("../res/vsftpd.crt");
|
||||
let cert = Certificate::from_pem(cert).unwrap();
|
||||
let mut ftp_stream = ftp_stream.into_secure(NativeTlsConnector::from(TlsConnector::builder().add_root_certificate(cert).build().unwrap()), "gitea.piwalker.net").unwrap();
|
||||
let result = ftp_stream.login(username, password);
|
||||
if result.is_ok() {
|
||||
return Ok(ftp_stream);
|
||||
}
|
||||
Err(result.unwrap_err())
|
||||
}
|
||||
|
||||
pub fn ftp_retr(window: Option<tauri::Window>, file: PathBuf , mut writer: impl Write, mut callback: impl FnMut(Option<tauri::Window>, usize, usize)) -> Result<bool, FtpError> {
|
||||
let mut ftp_stream = ftp_connection_anonymous()?;
|
||||
let file = file.to_str().unwrap().replace("\\", "/");
|
||||
let size = ftp_stream.size(&file)?;
|
||||
let mut total = 0;
|
||||
ftp_stream.retr(file.as_str(), |stream| {
|
||||
let mut tx_bytes = [0u8; 1500];
|
||||
loop {
|
||||
let bytes_read = stream.read(&mut tx_bytes).unwrap();
|
||||
writer.write_all(&mut tx_bytes.split_at(bytes_read).0).unwrap();
|
||||
total += bytes_read;
|
||||
if total == size || bytes_read == 0 {
|
||||
callback(window.clone(), 0, size);
|
||||
break;
|
||||
}else{
|
||||
callback(window.clone(), bytes_read, size);
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
})?;
|
||||
Ok(true)
|
||||
|
||||
}
|
||||
|
||||
pub fn ftp_get_size(file: PathBuf) -> Result<usize, FtpError> {
|
||||
let mut stream = ftp_connection_anonymous()?;
|
||||
stream.size(file.to_str().unwrap().replace("\\", "/"))
|
||||
}
|
||||
|
||||
|
||||
|
67
FCLauncher.old/src-tauri/src/https.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use futures_util::StreamExt;
|
||||
use serde::Serialize;
|
||||
use std::cmp::min;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use tauri::Emitter;
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
pub struct DownloadStatus {
|
||||
pub downloaded: usize,
|
||||
pub total: usize,
|
||||
pub time_elapsed: usize,
|
||||
pub download_name: String,
|
||||
}
|
||||
|
||||
pub async fn download(
|
||||
window: Option<tauri::AppHandle>,
|
||||
url: String,
|
||||
mut writer: impl Write,
|
||||
downloadName: String,
|
||||
) -> Result<(), String> {
|
||||
let client = reqwest::Client::new();
|
||||
let res = client
|
||||
.get(url)
|
||||
.send()
|
||||
.await
|
||||
.or(Err(format!("Failed to fetch from URL!")))?;
|
||||
let total_size = res
|
||||
.content_length()
|
||||
.ok_or(format!("Failed to get content length"))?;
|
||||
let mut downloaded: u64 = 0;
|
||||
let mut stream = res.bytes_stream();
|
||||
while let Some(item) = stream.next().await {
|
||||
let chunk = item.or(Err(format!("Error while downloading file!")))?;
|
||||
writer
|
||||
.write_all(&chunk)
|
||||
.or(Err("Error writing to stream!"))?;
|
||||
let new = min(downloaded + (chunk.len() as u64), total_size);
|
||||
downloaded = new;
|
||||
println!(
|
||||
"Downloading {}: {}MB / {}MB",
|
||||
downloadName.clone(),
|
||||
downloaded / (1024 * 1024),
|
||||
total_size / (1024 * 1024)
|
||||
);
|
||||
if let Some(window) = window.clone() {
|
||||
if downloaded != total_size {
|
||||
window
|
||||
.emit(
|
||||
"download_progress",
|
||||
DownloadStatus {
|
||||
downloaded: downloaded as usize,
|
||||
total: total_size as usize,
|
||||
time_elapsed: 0,
|
||||
download_name: downloadName.clone(),
|
||||
},
|
||||
)
|
||||
.or(Err(format!("Unable to signal window")))?;
|
||||
} else {
|
||||
window
|
||||
.emit("download_finished", true)
|
||||
.or(Err(format!("Unable to signal window!")))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
110
FCLauncher.old/src-tauri/src/java.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use flate2::read::GzDecoder;
|
||||
use std::env;
|
||||
use std::io::{Cursor, Read, Seek};
|
||||
use std::path::{Components, Path, PathBuf};
|
||||
use tar::Archive;
|
||||
|
||||
use crate::https;
|
||||
use crate::system_dirs::get_local_data_directory;
|
||||
use crate::util;
|
||||
|
||||
fn check_java(version: u8) -> bool {
|
||||
let dir = get_local_data_directory().join("java").join(format!(
|
||||
"java-{}-{}",
|
||||
version,
|
||||
if env::consts::OS == "windows" {
|
||||
"win"
|
||||
} else {
|
||||
"lin"
|
||||
}
|
||||
));
|
||||
dir.exists()
|
||||
}
|
||||
|
||||
pub async fn install_java(version: u8, window: tauri::AppHandle) {
|
||||
if check_java(version) {
|
||||
return;
|
||||
}
|
||||
//let ftp_dir = PathBuf::new().join("java").join(format!("java-{}-{}", version, if env::consts::OS == "windows" { "win.zip" } else {"lin.tar.gz"}));
|
||||
let mut buff = Cursor::new(vec![]);
|
||||
//ftp::ftp_retr(Some(window), ftp_dir, &mut buff, |window, data, size| util::download_callback(format!("Java {}", version), window,data, size)).unwrap();
|
||||
https::download(
|
||||
Some(window.clone()),
|
||||
format!(
|
||||
"https://gitea.piwalker.net/fclauncher/java/java-{}-{}",
|
||||
version,
|
||||
if env::consts::OS == "windows" {
|
||||
"win.zip"
|
||||
} else {
|
||||
"lin.tar.gz"
|
||||
}
|
||||
),
|
||||
&mut buff,
|
||||
format!("Java {}", version),
|
||||
)
|
||||
.await;
|
||||
std::fs::create_dir_all(get_local_data_directory().join("java").join(format!(
|
||||
"java-{}-{}",
|
||||
version,
|
||||
if env::consts::OS == "windows" {
|
||||
"win"
|
||||
} else {
|
||||
"lin"
|
||||
}
|
||||
)))
|
||||
.unwrap();
|
||||
buff.rewind().unwrap();
|
||||
if env::consts::OS != "windows" {
|
||||
let tar = GzDecoder::new(buff);
|
||||
let mut archive = Archive::new(tar);
|
||||
if !unpack_archive(
|
||||
archive,
|
||||
get_local_data_directory()
|
||||
.join("java")
|
||||
.join(format!("java-{}-lin", version)),
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
std::fs::remove_dir_all(
|
||||
get_local_data_directory()
|
||||
.join("java")
|
||||
.join(format!("java-{}-lin", version)),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
} else {
|
||||
if !zip_extract::extract(
|
||||
buff,
|
||||
get_local_data_directory()
|
||||
.join("java")
|
||||
.join(format!("java-{}-win", version))
|
||||
.as_path(),
|
||||
true,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
std::fs::remove_dir_all(
|
||||
get_local_data_directory()
|
||||
.join("java")
|
||||
.join(format!("java-{}-win", version)),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unpack_archive<T: Read>(
|
||||
mut archive: Archive<T>,
|
||||
dst: PathBuf,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
for file in archive.entries()? {
|
||||
let path = PathBuf::new().join(dst.clone());
|
||||
let mut file = file?;
|
||||
let file_path = file.path()?;
|
||||
let mut file_path = file_path.components();
|
||||
let _ = file_path.next();
|
||||
let file_path = file_path.as_path();
|
||||
file.unpack(path.join(file_path))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
60
FCLauncher.old/src-tauri/src/main.rs
Normal file
@ -0,0 +1,60 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use self_update::cargo_crate_version;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Result, Value};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::io::Seek;
|
||||
use std::{io::Cursor, path::PathBuf};
|
||||
|
||||
//mod ftp;
|
||||
mod admin;
|
||||
mod https;
|
||||
mod java;
|
||||
mod modpack;
|
||||
mod prism;
|
||||
mod sftp;
|
||||
mod system_dirs;
|
||||
mod util;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct ModpackEntry {
|
||||
name: String,
|
||||
id: String,
|
||||
}
|
||||
|
||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
//modpack::get_modpacks();
|
||||
//prism::install_prism();
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.plugin(tauri_plugin_process::init())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
greet,
|
||||
modpack::get_modpacks,
|
||||
modpack::launch_modpack,
|
||||
modpack::get_versions,
|
||||
modpack::get_latest_version,
|
||||
prism::launch_prism,
|
||||
prism::install_prism,
|
||||
admin::login,
|
||||
admin::drop_session,
|
||||
admin::shift_up,
|
||||
admin::shift_down,
|
||||
admin::add_pack,
|
||||
admin::remove_pack,
|
||||
admin::update_pack
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
324
FCLauncher.old/src-tauri/src/modpack.rs
Normal file
@ -0,0 +1,324 @@
|
||||
use crate::https;
|
||||
use crate::java;
|
||||
use crate::system_dirs::{
|
||||
get_data_directory, get_java_executable, get_local_data_directory, get_prism_executable,
|
||||
};
|
||||
use crate::util;
|
||||
use reqwest::IntoUrl;
|
||||
use serde::de::value::Error;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Seek, Write};
|
||||
use std::process::Command;
|
||||
use std::time::Duration;
|
||||
use std::{env, thread};
|
||||
use std::{io::Cursor, path::PathBuf};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct ModpackEntry {
|
||||
pub name: String,
|
||||
pub id: String,
|
||||
pub last_updated: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct VersionEntry {
|
||||
pub Version: String,
|
||||
pub File: String,
|
||||
pub Date: String,
|
||||
}
|
||||
|
||||
async fn get_modpack_name(id: String) -> String {
|
||||
let modpacks = get_modpacks().await;
|
||||
let mut instance_name = String::new();
|
||||
for pack in modpacks {
|
||||
if pack.id == id {
|
||||
instance_name = pack.name;
|
||||
}
|
||||
}
|
||||
return instance_name;
|
||||
}
|
||||
|
||||
async fn check_modpack_needs_update(id: String) -> bool {
|
||||
let mut instance_name = get_modpack_name(id.clone()).await;
|
||||
if !get_local_data_directory()
|
||||
.join("prism")
|
||||
.join("instances")
|
||||
.join(&mut instance_name)
|
||||
.exists()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
let versions = get_versions(id).await;
|
||||
if !versions.is_ok() {
|
||||
return false;
|
||||
}
|
||||
let versions = versions.unwrap();
|
||||
let latest = versions[versions.len() - 1].Version.clone();
|
||||
|
||||
let mut file = File::open(
|
||||
get_local_data_directory()
|
||||
.join("prism")
|
||||
.join("instances")
|
||||
.join(instance_name)
|
||||
.join(".minecraft")
|
||||
.join("version.txt"),
|
||||
)
|
||||
.unwrap();
|
||||
let mut current = String::new();
|
||||
file.read_to_string(&mut current);
|
||||
|
||||
if latest != current {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn launch_modpack(window: tauri::AppHandle, id: String) {
|
||||
if check_modpack_needs_update(id.clone()).await {
|
||||
install_modpack(window, id.clone()).await;
|
||||
}
|
||||
// Launch
|
||||
let mut child = Command::new(
|
||||
get_local_data_directory()
|
||||
.join("prism")
|
||||
.join(get_prism_executable()),
|
||||
)
|
||||
.arg("-l")
|
||||
.arg(get_modpack_name(id).await)
|
||||
.spawn()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn install_modpack(window: tauri::AppHandle, id: String) {
|
||||
let versions = get_versions(id.clone()).await.unwrap();
|
||||
let path = env::temp_dir().join(format!("{}.mrpack", get_modpack_name(id.clone()).await));
|
||||
let mut file = File::create(path.clone()).unwrap();
|
||||
let ftp_path = PathBuf::new()
|
||||
.join(id.clone())
|
||||
.join(versions[versions.len() - 1].File.clone().as_str());
|
||||
println!("Downloading file {}", ftp_path.to_str().unwrap());
|
||||
//ftp::ftp_retr(Some(window.clone()), ftp_path, &mut file, |window, data, size| util::download_callback(name.clone(), window, data, size)).unwrap();
|
||||
https::download(
|
||||
Some(window.clone()),
|
||||
format!(
|
||||
"https://gitea.piwalker.net/fclauncher/{}/{}",
|
||||
id.clone(),
|
||||
versions[versions.len() - 1].File.clone()
|
||||
),
|
||||
&mut file,
|
||||
get_modpack_name(id.clone()).await,
|
||||
)
|
||||
.await;
|
||||
let mut child = Command::new(
|
||||
get_local_data_directory()
|
||||
.join("prism")
|
||||
.join(get_prism_executable()),
|
||||
)
|
||||
.arg("-I")
|
||||
.arg(path)
|
||||
.spawn()
|
||||
.unwrap();
|
||||
loop {
|
||||
let version_path = get_local_data_directory()
|
||||
.join("prism")
|
||||
.join("instances")
|
||||
.join(get_modpack_name(id.clone()).await)
|
||||
.join(".minecraft")
|
||||
.join("version.txt");
|
||||
if version_path.clone().exists() {
|
||||
let mut ver_file = File::open(version_path).unwrap();
|
||||
let mut buf = String::new();
|
||||
ver_file.read_to_string(&mut buf).unwrap();
|
||||
if buf == versions[versions.len() - 1].Version.clone().as_str() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_secs(3));
|
||||
}
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
child.kill();
|
||||
let info_path = get_local_data_directory()
|
||||
.join("prism")
|
||||
.join("instances")
|
||||
.join(get_modpack_name(id.clone()).await)
|
||||
.join("mmc-pack.json");
|
||||
let mut info_file = File::open(info_path.clone()).unwrap();
|
||||
let info_json: Value = serde_json::from_reader(info_file).unwrap();
|
||||
let mut mc_version = "0.0";
|
||||
for component in info_json["components"].as_array().unwrap() {
|
||||
if component["uid"] == "net.minecraft" {
|
||||
mc_version = component["version"].as_str().unwrap();
|
||||
}
|
||||
}
|
||||
let java = get_java_version(mc_version);
|
||||
java::install_java(java, window.clone()).await;
|
||||
|
||||
let option_path = get_local_data_directory()
|
||||
.join("prism")
|
||||
.join("instances")
|
||||
.join(get_modpack_name(id.clone()).await)
|
||||
.join("instance.cfg");
|
||||
let mut option_file = File::open(option_path.clone()).unwrap();
|
||||
let mut buf = String::new();
|
||||
option_file.read_to_string(&mut buf);
|
||||
let mut option_file = File::create(option_path).unwrap();
|
||||
let mut set = false;
|
||||
for line in buf.lines() {
|
||||
if line.starts_with("JavaPath=") {
|
||||
option_file.write_all(
|
||||
format!(
|
||||
"JavaPath={}/java-{}-{}/bin/{}\n",
|
||||
get_local_data_directory()
|
||||
.join("java")
|
||||
.into_os_string()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.replace("\\", "/"),
|
||||
java,
|
||||
if env::consts::OS == "windows" {
|
||||
"win"
|
||||
} else {
|
||||
"lin"
|
||||
},
|
||||
get_java_executable()
|
||||
)
|
||||
.as_bytes(),
|
||||
);
|
||||
set = true;
|
||||
} else {
|
||||
option_file.write_all(format!("{}\n", line).as_bytes());
|
||||
}
|
||||
}
|
||||
if !set {
|
||||
option_file.write_all(
|
||||
format!(
|
||||
"JavaPath={}/java-{}-{}/bin/{}\n",
|
||||
get_local_data_directory()
|
||||
.join("java")
|
||||
.into_os_string()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.replace("\\", "/"),
|
||||
java,
|
||||
if env::consts::OS == "windows" {
|
||||
"win"
|
||||
} else {
|
||||
"lin"
|
||||
},
|
||||
get_java_executable()
|
||||
)
|
||||
.as_bytes(),
|
||||
);
|
||||
option_file.write_all("OverrideJavaLocation=true\n".as_bytes());
|
||||
option_file.write_all("OverrideJava=true\n".as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_modpacks() -> Vec<ModpackEntry> {
|
||||
//unsafe{
|
||||
let mut modpacks: Vec<ModpackEntry> = Vec::new();
|
||||
//if modpacks.is_empty() {
|
||||
let mut buf = Cursor::new(vec![]);
|
||||
//ftp::ftp_retr(None, PathBuf::new().join("modpacks.json"), &mut buf, |_, _, _| return);
|
||||
https::download(
|
||||
None,
|
||||
format!("https://gitea.piwalker.net/fclauncher/modpacks.json"),
|
||||
&mut buf,
|
||||
format!("modpacks.json"),
|
||||
)
|
||||
.await;
|
||||
buf.rewind();
|
||||
let res = serde_json::from_reader(buf);
|
||||
if !res.is_ok() {
|
||||
println!("Result not ok!");
|
||||
let paths =
|
||||
fs::read_dir(get_local_data_directory().join("prism").join("instances")).unwrap();
|
||||
for path in paths {
|
||||
let path = path.unwrap();
|
||||
if fs::metadata(path.path()).unwrap().is_file() {
|
||||
continue;
|
||||
}
|
||||
let name = path.file_name().into_string().unwrap();
|
||||
if name.starts_with(".") {
|
||||
continue;
|
||||
}
|
||||
|
||||
modpacks.push(ModpackEntry {
|
||||
name: name.clone(),
|
||||
id: name,
|
||||
last_updated: format!(""),
|
||||
})
|
||||
}
|
||||
return modpacks.clone();
|
||||
}
|
||||
let modpacks: Vec<ModpackEntry> = res.unwrap();
|
||||
//println!("{}", v[0].name);
|
||||
//for pack in v.as_array().unwrap() {
|
||||
//modpacks.push(ModpackEntry{name: pack["name"].as_str().unwrap().to_string(), id: pack["id"].as_str().unwrap().to_string(), last_updated: pack["last-updated"].as_str().unwrap().to_string()});
|
||||
//}
|
||||
//}
|
||||
return modpacks.clone();
|
||||
//}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_versions(id: String) -> Result<Vec<VersionEntry>, String> {
|
||||
let mut versions: Vec<VersionEntry> = Vec::new();
|
||||
let mut buf = Cursor::new(vec![]);
|
||||
//ftp::ftp_retr(None, PathBuf::new().join(id).join("versions.json"), &mut buf, |_, _, _| return);
|
||||
https::download(
|
||||
None,
|
||||
format!(
|
||||
"https://gitea.piwalker.net/fclauncher/{}/versions.json",
|
||||
id.clone()
|
||||
),
|
||||
&mut buf,
|
||||
format!("{}/versions.json", id.clone()),
|
||||
)
|
||||
.await;
|
||||
buf.rewind();
|
||||
let versions: Vec<VersionEntry> =
|
||||
serde_json::from_reader(buf).or(Err(format!("Unable to parse json")))?;
|
||||
//for version in v.as_array().unwrap() {
|
||||
//versions.push(VersionEntry{version: version["Version"].as_str().unwrap().to_string(), file: version["File"].as_str().unwrap().to_string(), date: version["Date"].as_str().unwrap().to_string()});
|
||||
//}
|
||||
return Ok(versions.clone());
|
||||
}
|
||||
|
||||
fn get_java_version(mc_version: &str) -> u8 {
|
||||
let components: Vec<&str> = mc_version.split(".").collect();
|
||||
let mut java = 8;
|
||||
if components[1] == "17" {
|
||||
java = 17
|
||||
} else if components[1] == "18" || components[1] == "19" {
|
||||
java = 17
|
||||
} else if components[1].parse::<i32>().unwrap() > 19 {
|
||||
if components[1] == "20" && components[1].parse::<i32>().unwrap() < 5 {
|
||||
java = 17
|
||||
} else {
|
||||
java = 21
|
||||
}
|
||||
}
|
||||
return java;
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_latest_version(id: String) -> Result<String, String> {
|
||||
let versions = get_versions(id).await.unwrap();
|
||||
if (versions.len() == 0) {
|
||||
return Ok(format!(""));
|
||||
}
|
||||
Ok(versions[versions.len() - 1].Version.clone())
|
||||
}
|
||||
|
||||
//pub fn create_json(modpacks: Vec<ModpackEntry>) -> Result<serde_json::Value, String> {
|
||||
|
||||
//}
|
124
FCLauncher.old/src-tauri/src/prism.rs
Normal file
@ -0,0 +1,124 @@
|
||||
use flate2::read::GzDecoder;
|
||||
use std::{
|
||||
env,
|
||||
fs::File,
|
||||
io::{BufRead, Cursor, Seek, Write},
|
||||
path::PathBuf,
|
||||
process::Command,
|
||||
str::FromStr,
|
||||
};
|
||||
use tar::Archive;
|
||||
//use tauri::file;
|
||||
|
||||
use crate::{
|
||||
https, java,
|
||||
system_dirs::{get_local_data_directory, get_prism_executable},
|
||||
util,
|
||||
};
|
||||
|
||||
pub fn check_prism() -> bool {
|
||||
let path = get_local_data_directory().join("prism");
|
||||
path.exists()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_prism(window: tauri::AppHandle) {
|
||||
if check_prism() {
|
||||
return;
|
||||
}
|
||||
java::install_java(21, window.clone()).await;
|
||||
let mut buff = Cursor::new(vec![]);
|
||||
let mut total = 0;
|
||||
//ftp::ftp_retr(Some(window.clone()), path, &mut buff, |window: Option<tauri::Window>, data, size| util::download_callback("Prism Launcher".to_string(),window, data, size)).unwrap();
|
||||
https::download(
|
||||
Some(window.clone()),
|
||||
format!(
|
||||
"https://gitea.piwalker.net/fclauncher/prism/prism-{}",
|
||||
if env::consts::OS == "windows" {
|
||||
"win.zip"
|
||||
} else {
|
||||
"lin.tar.gz"
|
||||
}
|
||||
),
|
||||
&mut buff,
|
||||
format!("Prism Launcher"),
|
||||
)
|
||||
.await;
|
||||
std::fs::create_dir_all(get_local_data_directory().join("prism")).unwrap();
|
||||
buff.rewind().unwrap();
|
||||
if env::consts::OS != "windows" {
|
||||
let tar = GzDecoder::new(buff);
|
||||
let mut archive = Archive::new(tar);
|
||||
if !archive
|
||||
.unpack(get_local_data_directory().join("prism"))
|
||||
.is_ok()
|
||||
{
|
||||
std::fs::remove_dir_all(get_local_data_directory().join("prism"));
|
||||
}
|
||||
} else {
|
||||
if !zip_extract::extract(
|
||||
buff,
|
||||
get_local_data_directory().join("prism").as_path(),
|
||||
true,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
std::fs::remove_dir_all(get_local_data_directory().join("prism"));
|
||||
}
|
||||
}
|
||||
|
||||
let mut buff = Cursor::new(vec![]);
|
||||
//ftp::ftp_retr(Some(window.clone()), PathBuf::new().join("prism").join("prismlauncher.cfg"), &mut buff, |_, _, _| return).unwrap();
|
||||
https::download(
|
||||
None,
|
||||
format!("https://gitea.piwalker.net/fclauncher/prism/prismlauncher.cfg"),
|
||||
&mut buff,
|
||||
format!("prismlauncher.cfg"),
|
||||
)
|
||||
.await;
|
||||
buff.rewind();
|
||||
let mut file = File::create(
|
||||
get_local_data_directory()
|
||||
.join("prism")
|
||||
.join("prismlauncher.cfg"),
|
||||
)
|
||||
.unwrap();
|
||||
loop {
|
||||
let mut buf = String::new();
|
||||
let count = buff.read_line(&mut buf).unwrap();
|
||||
if count == 0 {
|
||||
break;
|
||||
}
|
||||
if buf.starts_with("JavaPath") {
|
||||
buf = format!(
|
||||
"JavaPath={}/java/java-21-{}\n",
|
||||
get_local_data_directory()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.replace("\\", "/"),
|
||||
if env::consts::OS == "windows" {
|
||||
"win"
|
||||
} else {
|
||||
"lin"
|
||||
}
|
||||
);
|
||||
} else if buf.starts_with("LastHostname") {
|
||||
buf = format!(
|
||||
"LastHostname={}\n",
|
||||
gethostname::gethostname().to_str().unwrap()
|
||||
);
|
||||
}
|
||||
file.write_all(buf.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn launch_prism() {
|
||||
let mut child = Command::new(
|
||||
get_local_data_directory()
|
||||
.join("prism")
|
||||
.join(get_prism_executable()),
|
||||
)
|
||||
.spawn()
|
||||
.unwrap();
|
||||
}
|
102
FCLauncher.old/src-tauri/src/sftp.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use futures_util::future::BoxFuture;
|
||||
use futures_util::io::BufReader;
|
||||
use futures_util::io::Cursor;
|
||||
use futures_util::FutureExt;
|
||||
use ssh2::OpenFlags;
|
||||
use ssh2::Session;
|
||||
use ssh2::Sftp;
|
||||
use std::io::prelude::*;
|
||||
use std::net::TcpStream;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use tauri::Emitter;
|
||||
|
||||
use crate::https;
|
||||
|
||||
pub fn connect(username: String, password: String) -> Result<Session, String> {
|
||||
let tcp = TcpStream::connect("gitea.piwalker.net:22")
|
||||
.or(Err(format!("Unable to connect to host")))?;
|
||||
let mut sess = Session::new().or(Err(format!("Unable to creat stream")))?;
|
||||
sess.set_tcp_stream(tcp);
|
||||
sess.handshake().unwrap();
|
||||
sess.userauth_password(username.as_str(), password.as_str())
|
||||
.or(Err(format!("Invalid username or password")))?;
|
||||
Ok(sess)
|
||||
}
|
||||
|
||||
pub async fn uplaod(
|
||||
window: Option<tauri::AppHandle>,
|
||||
sess: Session,
|
||||
path: PathBuf,
|
||||
mut reader: impl Read,
|
||||
upload_name: String,
|
||||
total_size: usize,
|
||||
) -> Result<(), String> {
|
||||
let sftp = sess.sftp().or(Err("unable to open sftp session"))?;
|
||||
let mut file = sftp.create(path.as_path()).or(Err("Unable to open file"))?;
|
||||
let mut uploaded = 0;
|
||||
while true {
|
||||
let mut buf = vec![0u8; 1024 * 32];
|
||||
let res = reader.read(&mut buf).unwrap();
|
||||
if res <= 0 {
|
||||
if let Some(window) = window.clone() {
|
||||
window
|
||||
.emit("download_finished", true)
|
||||
.or(Err(format!("Unable to signal window!")))?;
|
||||
}
|
||||
break;
|
||||
}
|
||||
file.write_all(buf.split_at(res).0).unwrap();
|
||||
uploaded += res;
|
||||
println!(
|
||||
"Uploading {} {}MB / {}MB",
|
||||
upload_name,
|
||||
uploaded / (1024 * 1024),
|
||||
total_size / (1024 * 1024)
|
||||
);
|
||||
if let Some(window) = window.clone() {
|
||||
window
|
||||
.emit(
|
||||
"download_progress",
|
||||
https::DownloadStatus {
|
||||
downloaded: uploaded as usize,
|
||||
total: total_size as usize,
|
||||
time_elapsed: 0,
|
||||
download_name: upload_name.clone(),
|
||||
},
|
||||
)
|
||||
.or(Err(format!("Unable to signal window")))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn mkdir(sess: Session, path: PathBuf) -> Result<(), String> {
|
||||
let sftp = sess.sftp().or(Err("Unable to open sftp session"))?;
|
||||
sftp.mkdir(path.as_path(), 0o775)
|
||||
.or(Err(format!("Unable to create directory")))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn rmdir(sess: Session, path: PathBuf) -> BoxFuture<'static, ()> {
|
||||
async move {
|
||||
let sftp = sess.sftp().or(Err("Unable to open sftp session")).unwrap();
|
||||
let dirs = sftp
|
||||
.readdir(path.as_path())
|
||||
.or(Err("unable to stat directory"))
|
||||
.unwrap();
|
||||
for dir in dirs {
|
||||
if dir.1.is_dir() {
|
||||
rmdir(sess.clone(), dir.0).await;
|
||||
} else {
|
||||
sftp.unlink(dir.0.as_path())
|
||||
.or(Err(format!("Unable to delete file")))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
sftp.rmdir(path.as_path())
|
||||
.or(Err(format!("Unable to delete directory")))
|
||||
.unwrap();
|
||||
}
|
||||
.boxed()
|
||||
}
|
35
FCLauncher.old/src-tauri/src/system_dirs.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use dirs::home_dir;
|
||||
use std::{
|
||||
env,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
pub fn get_local_data_directory() -> PathBuf {
|
||||
dirs::data_local_dir().unwrap().join("FCLauncher")
|
||||
}
|
||||
|
||||
pub fn get_data_directory() -> PathBuf {
|
||||
dirs::data_dir().unwrap().join("FCLauncher")
|
||||
}
|
||||
|
||||
pub fn get_java_executable() -> String {
|
||||
return format!(
|
||||
"java{}",
|
||||
if env::consts::OS == "windows" {
|
||||
".exe"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
pub fn get_prism_executable() -> String {
|
||||
return format!(
|
||||
"{}",
|
||||
if env::consts::OS == "windows" {
|
||||
"prismlauncher.exe"
|
||||
} else {
|
||||
"PrismLauncher"
|
||||
}
|
||||
);
|
||||
}
|
46
FCLauncher.old/src-tauri/src/util.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use std::clone;
|
||||
use tauri::Emitter;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
pub struct DownloadStatus {
|
||||
downloaded: usize,
|
||||
total: usize,
|
||||
time_elapsed: usize,
|
||||
download_name: String,
|
||||
}
|
||||
|
||||
pub fn download_callback(
|
||||
download_name: String,
|
||||
window: Option<tauri::AppHandle>,
|
||||
count: usize,
|
||||
size: usize,
|
||||
) {
|
||||
unsafe {
|
||||
static mut total: usize = 0;
|
||||
total += count;
|
||||
if let Some(window1) = window.clone() {
|
||||
window1.emit(
|
||||
"download_progress",
|
||||
DownloadStatus {
|
||||
downloaded: total,
|
||||
total: size,
|
||||
time_elapsed: 0,
|
||||
download_name: download_name,
|
||||
},
|
||||
);
|
||||
}
|
||||
println!(
|
||||
"Downloading {}MB / {}MB",
|
||||
total / (1024 * 1024),
|
||||
size / (1024 * 1024)
|
||||
);
|
||||
if count == 0 {
|
||||
if let Some(window2) = window {
|
||||
window2.emit("download_finished", true);
|
||||
}
|
||||
total = 0;
|
||||
}
|
||||
}
|
||||
}
|
43
FCLauncher.old/src-tauri/tauri.conf.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"build": {
|
||||
"frontendDist": "../src"
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"createUpdaterArtifacts": "v1Compatible"
|
||||
},
|
||||
"productName": "FCLauncher",
|
||||
"mainBinaryName": "FCLauncher",
|
||||
"version": "1.0.5",
|
||||
"identifier": "net.piwalker",
|
||||
"plugins": {
|
||||
"updater": {
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDNDOEUwMjYxRUU2NEI5RgpSV1NmUytZZUp1RElBN3dEaGhpWG9JZVNQcFlnNFFzaXN0UnBsVmxNeVdWWnJoQmh4cGJRbjN3Ygo=",
|
||||
"endpoints": [
|
||||
"https://gitea.piwalker.net/fclauncher/app.json"
|
||||
]
|
||||
}
|
||||
},
|
||||
"app": {
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"withGlobalTauri": true,
|
||||
"windows": [
|
||||
{
|
||||
"title": "FCLauncher",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"resizable": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
60
FCLauncher.old/src-tauri/tauri.conf.json.old
Normal file
@ -0,0 +1,60 @@
|
||||
{
|
||||
"build": {
|
||||
"devPath": "../src",
|
||||
"distDir": "../src",
|
||||
"withGlobalTauri": true
|
||||
},
|
||||
"package": {
|
||||
"productName": "FCLauncher",
|
||||
"version": "1.0.5"
|
||||
},
|
||||
"tauri": {
|
||||
"updater": {
|
||||
"active": true,
|
||||
"endpoints": [
|
||||
"https://gitea.piwalker.net/fclauncher/app.json"
|
||||
],
|
||||
"dialog": true,
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDNDOEUwMjYxRUU2NEI5RgpSV1NmUytZZUp1RElBN3dEaGhpWG9JZVNQcFlnNFFzaXN0UnBsVmxNeVdWWnJoQmh4cGJRbjN3Ygo="
|
||||
},
|
||||
"allowlist": {
|
||||
"all": false,
|
||||
"shell": {
|
||||
"all": false,
|
||||
"open": true
|
||||
},
|
||||
"dialog": {
|
||||
"all": false,
|
||||
"ask": true,
|
||||
"open": true,
|
||||
"message": true
|
||||
},
|
||||
"process": {
|
||||
"all": true
|
||||
}
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"title": "FCLauncher",
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"resizable": false
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"identifier": "net.piwalker",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|