Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/ui/src/components/config-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type React from "react";
import { useEffect, useState } from "react";
import { type ZodType, z } from "zod";
import { MAX_DOWNLOAD_THREADS, MIN_DOWNLOAD_THREADS } from "@/lib/config";
import { useSettingsStore } from "@/models/settings";
import type { LauncherConfig } from "@/types";
import { Button } from "./ui/button";
Expand All @@ -22,7 +23,10 @@ const launcherConfigSchema: ZodType<LauncherConfig> = z.object({
javaPath: z.string(),
width: z.number(),
height: z.number(),
downloadThreads: z.number(),
downloadThreads: z
.number()
.min(MIN_DOWNLOAD_THREADS)
.max(MAX_DOWNLOAD_THREADS),
customBackgroundPath: z.string().nullable(),
enableGpuAcceleration: z.boolean(),
enableVisualEffects: z.boolean(),
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const MIN_DOWNLOAD_THREADS = 1;
export const MAX_DOWNLOAD_THREADS = 64;
5 changes: 3 additions & 2 deletions packages/ui/src/pages/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
import { Spinner } from "@/components/ui/spinner";
import { Switch } from "@/components/ui/switch";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { MAX_DOWNLOAD_THREADS, MIN_DOWNLOAD_THREADS } from "@/lib/config";
import { useJavaStore } from "@/models/java";
import { useSettingsStore } from "@/models/settings";

Expand Down Expand Up @@ -168,8 +169,8 @@ export function SettingsPage() {
onBlur={() => {
settings.save();
}}
min={1}
max={64}
min={MIN_DOWNLOAD_THREADS}
max={MAX_DOWNLOAD_THREADS}
/>
</Field>
</FieldSet>
Expand Down
23 changes: 19 additions & 4 deletions src-tauri/src/core/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use std::sync::Mutex;
use tauri::{AppHandle, Manager};
use ts_rs::TS;

pub const MIN_DOWNLOAD_THREADS: u32 = 1;
pub const MAX_DOWNLOAD_THREADS: u32 = 64;

#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export, export_to = "config.ts")]
Expand Down Expand Up @@ -85,7 +88,8 @@ pub struct LauncherConfig {
pub java_path: String,
pub width: u32,
pub height: u32,
pub download_threads: u32, // concurrent download threads (1-128)
/// Concurrent download threads. Clamped via MIN_DOWNLOAD_THREADS/MAX_DOWNLOAD_THREADS.
pub download_threads: u32,
pub custom_background_path: Option<String>,
pub enable_gpu_acceleration: bool,
pub enable_visual_effects: bool,
Expand All @@ -109,7 +113,7 @@ impl Default for LauncherConfig {
java_path: "java".to_string(),
width: 854,
height: 480,
download_threads: 32,
download_threads: 8,
custom_background_path: None,
enable_gpu_acceleration: false,
enable_visual_effects: true,
Expand All @@ -125,6 +129,14 @@ impl Default for LauncherConfig {
}
}

impl LauncherConfig {
pub fn sanitize(&mut self) {
self.download_threads =
self.download_threads
.clamp(MIN_DOWNLOAD_THREADS, MAX_DOWNLOAD_THREADS);
}
}

pub struct ConfigState {
pub config: Mutex<LauncherConfig>,
pub file_path: PathBuf,
Expand All @@ -137,7 +149,9 @@ impl ConfigState {

let config = if config_path.exists() {
let content = fs::read_to_string(&config_path).unwrap_or_default();
serde_json::from_str(&content).unwrap_or_default()
let mut config: LauncherConfig = serde_json::from_str(&content).unwrap_or_default();
config.sanitize();
config
} else {
LauncherConfig::default()
};
Expand All @@ -150,7 +164,8 @@ impl ConfigState {

pub fn save(&self) -> Result<(), String> {
let config = self.config.lock().unwrap();
let content = serde_json::to_string_pretty(&*config).map_err(|e| e.to_string())?;
let content = serde_json::to_string_pretty(&*config)
.map_err(|e| format!("Failed to serialize config: {}", e))?;
fs::create_dir_all(self.file_path.parent().unwrap()).map_err(|e| e.to_string())?;
fs::write(&self.file_path, content).map_err(|e| e.to_string())?;
Ok(())
Expand Down
8 changes: 6 additions & 2 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1646,11 +1646,15 @@ async fn save_raw_config(
content: String,
) -> Result<(), String> {
// Validate JSON
let new_config: core::config::LauncherConfig =
let mut new_config: core::config::LauncherConfig =
serde_json::from_str(&content).map_err(|e| format!("Invalid JSON: {}", e))?;
new_config.sanitize();

let normalized_content = serde_json::to_string_pretty(&new_config)
.map_err(|e| format!("Failed to serialize config: {}", e))?;

// Save to file
tokio::fs::write(&state.file_path, &content)
tokio::fs::write(&state.file_path, &normalized_content)
.await
.map_err(|e| e.to_string())?;

Expand Down