use log; use std::fs::{self, File}; use tokio::io::AsyncWriteExt; use tokio::sync::Mutex; use crate::pkg_remote; use crate::pkg_local; use crate::util; use crate::{types, AppData}; use crate::types::{local, Package}; use tauri::State; #[tauri::command] pub async fn startline( state: State<'_, Mutex>, ) -> Result, ()> { log::debug!("invoke: startline"); let appd = state.lock().await; Ok(appd.profile.clone()) } #[tauri::command] pub async fn download_package(pkg: Package) { log::debug!("invoke: download_package"); use futures::StreamExt; let zip_path = util::get_dirs().cache_dir().join(format!( "{}-{}-{}.zip", pkg.namespace, pkg.name, pkg.version )); if !zip_path.exists() { // let zip_path_part = zip_path.add_extension("part"); let mut zip_path_part = zip_path.clone(); zip_path_part.set_extension("zip.part"); let mut cache_file_w = tokio::fs::File::create(&zip_path_part).await.unwrap(); let mut byte_stream = reqwest::get(&pkg.download_url) .await .unwrap() .bytes_stream(); log::info!("downloading: {}", pkg.download_url); while let Some(item) = byte_stream.next().await { let i = item.unwrap(); cache_file_w.write_all(&mut i.as_ref()).await.unwrap(); } cache_file_w.sync_all().await.unwrap(); tokio::fs::rename(&zip_path_part, &zip_path).await.unwrap(); } let cache_file_r = File::open(&zip_path).unwrap(); let mut archive = zip::ZipArchive::new(cache_file_r).unwrap(); delete_package(pkg.namespace.clone(), pkg.name.clone()) .await .unwrap(); let path = util::get_dirs() .data_dir() .join("pkg") .join(format!("{}-{}", pkg.namespace, pkg.name)); fs::create_dir(&path).unwrap(); archive.extract(path).unwrap(); } #[tauri::command] pub async fn delete_package(namespace: String, name: String) -> Result<(), String> { log::debug!("invoke: download_package"); let path = util::get_dirs() .data_dir() .join("pkg") .join(format!("{}-{}", namespace, name)); if path.exists() && path.join("manifest.json").exists() { log::debug!("rm -r'ing {}", path.to_string_lossy()); return tokio::fs::remove_dir_all(&path) .await .map_err(|e| e.to_string()); } Ok(()) } #[tauri::command] pub async fn reload_packages(state: State<'_, tokio::sync::Mutex>) -> Result<(), ()> { log::debug!("invoke: reload_packages"); let mut appd = state.lock().await; // todo: this should only fetch new things appd.mods_local = pkg_local::walk_packages(false).await; Ok(()) } #[tauri::command] pub async fn get_packages(state: State<'_, Mutex>) -> Result, ()> { log::debug!("invoke: get_packages"); let appd = state.lock().await; log::debug!("Returning {} packages", appd.mods_local.len()); Ok(appd.mods_local.clone()) } #[tauri::command] pub async fn get_listings(state: State<'_, Mutex>) -> Result, String> { log::debug!("invoke: get_listings"); let should_fetch; { let appd = state.lock().await; should_fetch = appd.mods_store.len() == 0; } if should_fetch { let listings = pkg_remote::fetch_listings().await?; let mut appd = state.lock().await; appd.mods_store = listings; Ok(appd.mods_store.clone()) } else { let appd = state.lock().await; Ok(appd.mods_store.clone()) } } #[tauri::command] pub async fn get_current_profile( state: State<'_, Mutex>, ) -> Result, ()> { log::debug!("invoke: get_current_profile"); let appd = state.lock().await; Ok(appd.profile.clone()) } #[tauri::command] pub async fn save_profile( state: State<'_, Mutex> ) -> Result<(), ()> { log::debug!("invoke: save_profile"); let appd = state.lock().await; if let Some(profile) = &appd.profile { let path = util::get_dirs().config_dir().join("profile-ongeki-default.json"); let s = serde_json::to_string_pretty(profile).unwrap(); tokio::fs::write(&path, s).await.unwrap(); log::info!("Written to {}", path.to_string_lossy()); } else { log::error!("No profile to save"); } Ok(()) } #[tauri::command] pub async fn init_profile( state: State<'_, Mutex>, path: String ) -> Result { log::debug!("invoke: init_profile"); let new_profile = local::Profile { game: types::misc::Game::Ongeki, path: path, name: "ongeki-default".to_owned(), mods: [].to_vec() }; { let mut appd = state.lock().await; appd.profile = Some(new_profile.clone()); } save_profile(state).await.unwrap(); Ok(new_profile) }