feat: initial chunithm support

This commit is contained in:
2025-03-19 17:39:12 +00:00
parent 1191cdd95c
commit 8ac45df3e1
31 changed files with 1368 additions and 884 deletions

View File

@ -5,15 +5,20 @@ use serde::{Deserialize, Serialize};
use tauri::{AppHandle, Emitter};
use tokio::fs;
use tokio::task::JoinSet;
use crate::model::local::{PackageList, PackageListEntry};
use crate::model::misc::Game;
use crate::model::rainy;
use crate::pkg::{Package, PkgKey, Remote};
use crate::pkg::{Package, PkgKey, Remote, Status};
use crate::util;
use crate::download_handler::DownloadHandler;
pub struct PackageStore {
store: HashMap<PkgKey, Package>,
app: AppHandle,
meta_list: PackageList,
dlh: DownloadHandler,
app: AppHandle,
offline: bool,
}
@ -29,8 +34,17 @@ pub enum InstallResult {
impl PackageStore {
pub fn new(app: AppHandle) -> PackageStore {
let meta_list = std::fs::read_to_string(util::config_dir().join("package-list.json"))
.map_err(|e| anyhow!(e))
.and_then(|s| serde_json::from_str::<PackageList>(&s).map_err(|e| anyhow!(e)))
.unwrap_or_else(|e| {
log::warn!("unable to read package-list: {e}");
PackageList::new()
});
PackageStore {
store: HashMap::new(),
meta_list,
app: app.clone(),
dlh: DownloadHandler::new(app),
offline: true
@ -46,6 +60,13 @@ impl PackageStore {
self.store.clone()
}
pub fn get_game_list(&self, game: Game) -> Vec<PkgKey> {
self.meta_list.iter()
.filter(|(_, v)| v.games.contains(&game))
.map(|(k, _)| k.clone())
.collect()
}
pub async fn reload_package(&mut self, key: PkgKey) {
let dir = util::pkg_dir().join(&key.0);
if let Ok(pkg) = Package::from_dir(dir).await {
@ -75,14 +96,23 @@ impl PackageStore {
Ok(())
}
pub async fn fetch_listings() -> Result<Vec<rainy::V1Package>> {
pub async fn save(&self) -> Result<()> {
tokio::fs::write(
util::config_dir().join("package-list.json"),
serde_json::to_string_pretty(&self.meta_list)?
).await?;
Ok(())
}
pub async fn fetch_listings(game: Game) -> Result<Vec<rainy::V1Package>> {
use async_compression::futures::bufread::GzipDecoder;
use futures::{
io::{self, BufReader, ErrorKind},
prelude::*,
};
let response = reqwest::get("https://rainy.patafour.zip/c/ongeki/api/v1/package/").await?;
let response = reqwest::get(format!("https://rainy.patafour.zip/c/{game}/api/v1/package/")).await?;
let reader = response
.bytes_stream()
@ -100,11 +130,23 @@ impl PackageStore {
self.offline
}
pub fn process_fetched_listings(&mut self, listings: Vec<rainy::V1Package>) {
pub fn process_fetched_listings(&mut self, listings: Vec<rainy::V1Package>, game: Game) {
for listing in listings {
// This is None if the package has no versions for whatever reason
if let Some(r) = Package::from_rainy(listing) {
//log::warn!("D {}", &r.rmt.as_ref().unwrap().dependencies.first().unwrap_or(&"Nothing".to_owned()));
let mut meta_entry = self.meta_list.remove(&r.key()).unwrap_or_else(|| {
PackageListEntry {
// from_rainy() is guaranteed to include rmt
version: r.rmt.as_ref().unwrap().version.clone(),
status: Status::Unchecked,
games: vec![ game ],
}
});
if !meta_entry.games.contains(&game) {
meta_entry.games.push(game);
}
self.meta_list.insert(r.key(), meta_entry);
match self.store.get_mut(&r.key()) {
Some(l) => {
l.rmt = r.rmt;
@ -226,9 +268,8 @@ impl PackageStore {
async fn clean_up_file(path: impl AsRef<Path>, name: &str, force: bool) -> Result<()> {
let path = path.as_ref().join(name);
if force || path.exists() {
tokio::fs::remove_file(path)
.await
.map_err(|e| anyhow!("Could not delete /{}: {}", name, e))?;
tokio::fs::remove_file(path).await
.map_err(|e| anyhow!("Could not delete /{}: {}", name, e))?;
}
Ok(())
@ -242,6 +283,7 @@ impl PackageStore {
Self::clean_up_file(&path, "icon.png", true).await?;
Self::clean_up_file(&path, "manifest.json", true).await?;
Self::clean_up_file(&path, "README.md", true).await?;
Self::clean_up_file(&path, "post_load.ps1", false).await?;
tokio::fs::remove_dir(path.as_ref())
.await