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 = parking_lot::const_mutex(String::new()); //static PASSWORD: parking_lot::Mutex = parking_lot::const_mutex(String::new()); static SESSION: tauri::async_runtime::Mutex> = 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) -> 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) -> 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 = 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(()) }