diff options
| author | salmonik <salmonik@tuta.io> | 2026-07-29 01:03:24 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-07-29 01:03:24 +0200 |
| commit | 74d2ada067bd2fd9436710ab7ac260e0eddf1314 (patch) | |
| tree | 1f791bb895a611d8e729a735ba098a647808a157 /src/routes/backups.rs | |
| parent | create example config on startup (diff) | |
| download | minecraft-ui-74d2ada067bd2fd9436710ab7ac260e0eddf1314.tar.gz minecraft-ui-74d2ada067bd2fd9436710ab7ac260e0eddf1314.zip | |
Add per-instance mod management with client-side detection
- New mod validation engine (src/mods.rs) with constant-pool class-file
scanning: detects server-side content (block, tileentity, command,
worldgen) vs client-only API (gui, renderer, forge/client)
- 7 client-only mods correctly detected (AppleSkin, CraftingTweaks,
Durability101, EnchantmentDescriptions, InventoryHUD, MouseTweaks,
TrashSlot); 51 server-capable; 1 unknown
- Routes + templating for mod upload (jar/zip), listing, delete, rescan
- Multipart upload with 500MB limit (bypasses axum's default 2MB)
- Per-instance mod summary card on edit page
- Whitelist toggle checkbox on edit page (persisted, drives ENABLE_WHITELIST)
- Dynamic Java image tag (java8/java17/java21) based on MC version
- Class scan is informational-only; rejection based on metadata side=CLIENT
- has_modpack flag cleanup on mod delete
- Remove hx-boost from <body> (was corrupting multipart uploads)
Diffstat (limited to 'src/routes/backups.rs')
| -rw-r--r-- | src/routes/backups.rs | 8 |
1 files changed, 3 insertions, 5 deletions
diff --git a/src/routes/backups.rs b/src/routes/backups.rs index 6f7617e..d68be8d 100644 --- a/src/routes/backups.rs +++ b/src/routes/backups.rs | |||
| @@ -119,14 +119,12 @@ async fn create_backup( | |||
| 119 | if let Ok(entries) = std::fs::read_dir(&data_dir) { | 119 | if let Ok(entries) = std::fs::read_dir(&data_dir) { |
| 120 | for entry in entries.flatten() { | 120 | for entry in entries.flatten() { |
| 121 | let path = entry.path(); | 121 | let path = entry.path(); |
| 122 | if path.is_file() { | 122 | if path.is_file() |
| 123 | if let Some(name) = path.file_name() { | 123 | && let Some(name) = path.file_name() |
| 124 | if let Ok(contents) = std::fs::read(&path) { | 124 | && let Ok(contents) = std::fs::read(&path) { |
| 125 | let _ = zip.start_file(&*name.to_string_lossy(), options); | 125 | let _ = zip.start_file(&*name.to_string_lossy(), options); |
| 126 | let _ = std::io::Write::write_all(&mut zip, &contents); | 126 | let _ = std::io::Write::write_all(&mut zip, &contents); |
| 127 | } | 127 | } |
| 128 | } | ||
| 129 | } | ||
| 130 | } | 128 | } |
| 131 | } | 129 | } |
| 132 | let _ = zip.finish(); | 130 | let _ = zip.finish(); |
