Skip to content

Commit 2e502b1

Browse files
authored
Merge pull request #63 from qianmoQ/dev-25.0.4
feat: 支持 Scala 语言环境安装
2 parents 5c87bbd + 83e628e commit 2e502b1

File tree

21 files changed

+1836
-112
lines changed

21 files changed

+1836
-112
lines changed

src-tauri/Cargo.lock

Lines changed: 331 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ tauri-build = { version = "2", features = [] }
1414
chrono = { version = "0.4.41", features = ["serde"] }
1515

1616
[dependencies]
17-
tauri = { version = "2", features = ["devtools"] }
18-
tauri-plugin-opener = "2"
17+
tauri = { version = "2.9", features = ["devtools"] }
18+
tauri-plugin-opener = "2.5"
1919
tauri-plugin-shell = "2.0"
20-
tauri-plugin-dialog = "2.0"
20+
tauri-plugin-dialog = "2.4"
2121
tauri-plugin-fs = "2.4.2"
2222
serde = { version = "1", features = ["derive"] }
2323
serde_json = "1"
@@ -33,3 +33,7 @@ reqwest = { version = "0.11", features = ["json", "stream"] }
3333
futures-util = "0.3"
3434
rfd = "0.15"
3535
fix-path-env = { git = "https://github.com/tauri-apps/fix-path-env-rs" }
36+
async-trait = "0.1"
37+
zip = "2.2.2"
38+
flate2 = "1.0"
39+
tar = "0.4"

src-tauri/src/env_commands.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use crate::env_manager::{EnvironmentInfo, EnvironmentManager};
2+
use log::info;
3+
use tauri::{AppHandle, State};
4+
use tokio::sync::Mutex;
5+
6+
pub type EnvironmentManagerState = Mutex<EnvironmentManager>;
7+
8+
#[tauri::command]
9+
pub async fn get_environment_info(
10+
language: String,
11+
env_manager: State<'_, EnvironmentManagerState>,
12+
) -> Result<EnvironmentInfo, String> {
13+
info!("获取 {} 环境信息", language);
14+
let manager = env_manager.lock().await;
15+
manager.get_environment_info(&language).await
16+
}
17+
18+
#[tauri::command]
19+
pub async fn download_and_install_version(
20+
language: String,
21+
version: String,
22+
app_handle: AppHandle,
23+
env_manager: State<'_, EnvironmentManagerState>,
24+
) -> Result<String, String> {
25+
info!("下载并安装 {} 版本 {}", language, version);
26+
let manager = env_manager.lock().await;
27+
manager
28+
.download_and_install_version(&language, &version, app_handle)
29+
.await
30+
}
31+
32+
#[tauri::command]
33+
pub async fn switch_environment_version(
34+
language: String,
35+
version: String,
36+
env_manager: State<'_, EnvironmentManagerState>,
37+
) -> Result<(), String> {
38+
info!("切换 {} 到版本 {}", language, version);
39+
let manager = env_manager.lock().await;
40+
manager.switch_version(&language, &version).await
41+
}
42+
43+
#[tauri::command]
44+
pub async fn get_supported_environment_languages(
45+
env_manager: State<'_, EnvironmentManagerState>,
46+
) -> Result<Vec<String>, String> {
47+
let manager = env_manager.lock().await;
48+
Ok(manager.get_supported_languages())
49+
}

src-tauri/src/env_manager.rs

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
use async_trait::async_trait;
2+
use log::{error, info};
3+
use serde::{Deserialize, Serialize};
4+
use std::collections::HashMap;
5+
use std::path::PathBuf;
6+
use tauri::{AppHandle, Emitter};
7+
8+
// 环境版本信息
9+
#[derive(Debug, Serialize, Deserialize, Clone)]
10+
pub struct EnvironmentVersion {
11+
pub version: String,
12+
pub download_url: String,
13+
pub install_path: Option<String>,
14+
pub is_installed: bool,
15+
pub size: Option<u64>,
16+
pub release_date: Option<String>,
17+
}
18+
19+
// 环境管理器响应
20+
#[derive(Debug, Serialize, Deserialize)]
21+
pub struct EnvironmentInfo {
22+
pub language: String,
23+
pub current_version: Option<String>,
24+
pub installed_versions: Vec<EnvironmentVersion>,
25+
pub available_versions: Vec<EnvironmentVersion>,
26+
}
27+
28+
// 下载进度事件
29+
#[derive(Debug, Serialize, Clone)]
30+
pub struct DownloadProgress {
31+
pub language: String,
32+
pub version: String,
33+
pub downloaded: u64,
34+
pub total: u64,
35+
pub percentage: f64,
36+
pub status: DownloadStatus,
37+
}
38+
39+
#[derive(Debug, Serialize, Clone)]
40+
#[serde(rename_all = "lowercase")]
41+
pub enum DownloadStatus {
42+
Downloading,
43+
Extracting,
44+
Installing,
45+
Completed,
46+
_Failed,
47+
}
48+
49+
// 语言环境提供者特征
50+
#[async_trait]
51+
pub trait EnvironmentProvider: Send + Sync {
52+
// 获取语言名称
53+
fn get_language(&self) -> &'static str;
54+
55+
// 获取可用版本列表
56+
async fn fetch_available_versions(&self) -> Result<Vec<EnvironmentVersion>, String>;
57+
58+
// 获取已安装版本列表
59+
async fn get_installed_versions(&self) -> Result<Vec<EnvironmentVersion>, String>;
60+
61+
// 下载并安装指定版本
62+
async fn download_and_install(
63+
&self,
64+
version: &str,
65+
app_handle: AppHandle,
66+
) -> Result<String, String>;
67+
68+
// 切换到指定版本
69+
async fn switch_version(&self, version: &str) -> Result<(), String>;
70+
71+
// 获取当前激活的版本
72+
async fn get_current_version(&self) -> Result<Option<String>, String>;
73+
74+
// 获取安装目录
75+
#[allow(dead_code)]
76+
fn get_install_dir(&self) -> PathBuf;
77+
}
78+
79+
// 环境管理器
80+
pub struct EnvironmentManager {
81+
providers: HashMap<String, Box<dyn EnvironmentProvider>>,
82+
}
83+
84+
impl EnvironmentManager {
85+
pub fn new() -> Self {
86+
Self {
87+
providers: HashMap::new(),
88+
}
89+
}
90+
91+
pub fn register_provider(&mut self, provider: Box<dyn EnvironmentProvider>) {
92+
let language = provider.get_language().to_string();
93+
info!("注册环境提供者: {}", language);
94+
self.providers.insert(language, provider);
95+
}
96+
97+
pub async fn get_environment_info(&self, language: &str) -> Result<EnvironmentInfo, String> {
98+
let provider = self
99+
.providers
100+
.get(language)
101+
.ok_or_else(|| format!("暂未支持 {} 语言,请前往 github 提供 issus", language))?;
102+
103+
info!("获取 {} 环境信息", language);
104+
105+
let current_version = provider.get_current_version().await.ok().flatten();
106+
let installed_versions = provider.get_installed_versions().await.unwrap_or_default();
107+
let available_versions = provider
108+
.fetch_available_versions()
109+
.await
110+
.unwrap_or_default();
111+
112+
Ok(EnvironmentInfo {
113+
language: language.to_string(),
114+
current_version,
115+
installed_versions,
116+
available_versions,
117+
})
118+
}
119+
120+
pub async fn download_and_install_version(
121+
&self,
122+
language: &str,
123+
version: &str,
124+
app_handle: AppHandle,
125+
) -> Result<String, String> {
126+
let provider = self
127+
.providers
128+
.get(language)
129+
.ok_or_else(|| format!("暂未支持 {} 语言,请前往 github 提供 issus", language))?;
130+
131+
info!("开始下载并安装 {} 版本 {}", language, version);
132+
provider.download_and_install(version, app_handle).await
133+
}
134+
135+
pub async fn switch_version(&self, language: &str, version: &str) -> Result<(), String> {
136+
let provider = self
137+
.providers
138+
.get(language)
139+
.ok_or_else(|| format!("暂未支持 {} 语言,请前往 github 提供 issus", language))?;
140+
141+
info!("切换 {} 到版本 {}", language, version);
142+
provider.switch_version(version).await
143+
}
144+
145+
pub fn get_supported_languages(&self) -> Vec<String> {
146+
self.providers.keys().cloned().collect()
147+
}
148+
}
149+
150+
// 辅助函数:发送下载进度事件
151+
pub fn emit_download_progress(
152+
app_handle: &AppHandle,
153+
language: &str,
154+
version: &str,
155+
downloaded: u64,
156+
total: u64,
157+
status: DownloadStatus,
158+
) {
159+
let percentage = if total > 0 {
160+
(downloaded as f64 / total as f64) * 100.0
161+
} else {
162+
0.0
163+
};
164+
165+
let progress = DownloadProgress {
166+
language: language.to_string(),
167+
version: version.to_string(),
168+
downloaded,
169+
total,
170+
percentage,
171+
status,
172+
};
173+
174+
if let Err(e) = app_handle.emit("env-download-progress", progress) {
175+
error!("发送下载进度事件失败: {}", e);
176+
}
177+
}

src-tauri/src/env_providers/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub mod scala;
2+
3+
pub use scala::ScalaEnvironmentProvider;

0 commit comments

Comments
 (0)