Skip to content

Commit 91ec62b

Browse files
committed
feat: 统一使用 CDN
1 parent 78dc58f commit 91ec62b

File tree

4 files changed

+180
-89
lines changed

4 files changed

+180
-89
lines changed

src-tauri/src/env_providers/clojure.rs

Lines changed: 17 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::metadata::{Metadata, fetch_metadata_from_cdn, is_cdn_enabled, is_fallback_enabled};
12
use crate::env_manager::{
23
DownloadStatus, EnvironmentProvider, EnvironmentVersion, emit_download_progress,
34
};
@@ -22,25 +23,6 @@ struct GithubAsset {
2223
size: u64,
2324
}
2425

25-
// CDN Metadata 结构
26-
#[derive(Debug, Deserialize, Serialize, Clone)]
27-
struct MetadataRelease {
28-
version: String, // 版本号,如 "1.11.1.1262"
29-
display_name: String, // 显示名称,如 "Clojure 1.11.1.1262"
30-
published_at: String, // 发布时间
31-
download_url: String, // CDN 下载地址
32-
github_url: String, // GitHub 官方下载地址(作为备用)
33-
file_name: String, // 文件名,如 "clojure-tools-1.11.1.1262.tar.gz"
34-
size: u64, // 文件大小(字节)
35-
supported_platforms: Vec<String>, // 支持的平台,如 ["macos", "linux", "windows"]
36-
}
37-
38-
#[derive(Debug, Deserialize, Serialize)]
39-
struct Metadata {
40-
language: String, // 语言名称 "clojure"
41-
releases: Vec<MetadataRelease>,
42-
}
43-
4426
#[derive(Debug, Deserialize, Serialize)]
4527
struct CachedReleases {
4628
releases: Vec<GithubRelease>,
@@ -185,56 +167,6 @@ impl ClojureEnvironmentProvider {
185167
Ok(versions)
186168
}
187169

188-
// 从 CDN 获取 metadata.json
189-
async fn fetch_metadata_from_cdn(&self) -> Result<Metadata, String> {
190-
use crate::config::get_app_config_internal;
191-
192-
let config = get_app_config_internal().map_err(|e| format!("读取配置失败: {}", e))?;
193-
194-
let cdn_enabled = config
195-
.environment_mirror
196-
.as_ref()
197-
.and_then(|m| m.enabled)
198-
.unwrap_or(false);
199-
200-
if !cdn_enabled {
201-
return Err("CDN 未启用".to_string());
202-
}
203-
204-
let base_url = config
205-
.environment_mirror
206-
.as_ref()
207-
.and_then(|m| m.base_url.as_ref())
208-
.ok_or("CDN 地址未配置")?;
209-
210-
let metadata_url = format!("{}/clojure/metadata.json", base_url);
211-
info!("从 CDN 获取 Clojure metadata: {}", metadata_url);
212-
213-
let client = reqwest::Client::builder()
214-
.user_agent("CodeForge")
215-
.timeout(Duration::from_secs(30))
216-
.build()
217-
.map_err(|e| format!("创建 HTTP 客户端失败: {}", e))?;
218-
219-
let response = client
220-
.get(&metadata_url)
221-
.send()
222-
.await
223-
.map_err(|e| format!("请求 CDN metadata 失败: {}", e))?;
224-
225-
if !response.status().is_success() {
226-
return Err(format!("CDN 返回错误状态码: {}", response.status()));
227-
}
228-
229-
let metadata: Metadata = response
230-
.json()
231-
.await
232-
.map_err(|e| format!("解析 metadata.json 失败: {}", e))?;
233-
234-
info!("成功从 CDN 获取 {} 个版本", metadata.releases.len());
235-
Ok(metadata)
236-
}
237-
238170
async fn fetch_github_releases(&self) -> Result<Vec<GithubRelease>, String> {
239171
if let Some(cached_releases) = self.read_cache() {
240172
return Ok(cached_releases);
@@ -636,30 +568,26 @@ impl EnvironmentProvider for ClojureEnvironmentProvider {
636568
}
637569

638570
async fn fetch_available_versions(&self) -> Result<Vec<EnvironmentVersion>, String> {
639-
use crate::config::get_app_config_internal;
640-
641-
// 优先尝试从 CDN 获取 metadata.json
642-
match self.fetch_metadata_from_cdn().await {
643-
Ok(metadata) => {
644-
info!("使用 CDN metadata 获取版本列表");
645-
return self.parse_metadata_to_versions(metadata);
646-
}
647-
Err(e) => {
648-
warn!("CDN metadata 获取失败: {}", e);
571+
// 检查 CDN 是否启用
572+
if is_cdn_enabled() {
573+
match fetch_metadata_from_cdn("clojure").await {
574+
Ok(metadata) => {
575+
info!("使用 CDN metadata 获取版本列表");
576+
return self.parse_metadata_to_versions(metadata);
577+
}
578+
Err(e) => {
579+
warn!("CDN metadata 获取失败: {}", e);
649580

650-
// 检查是否启用 fallback
651-
let fallback_enabled = get_app_config_internal()
652-
.ok()
653-
.and_then(|config| config.environment_mirror)
654-
.and_then(|mirror| mirror.fallback_enabled)
655-
.unwrap_or(false);
581+
// 检查是否启用 fallback
582+
if !is_fallback_enabled() {
583+
return Err(format!("CDN metadata 获取失败,未启用自动回退: {}", e));
584+
}
656585

657-
if !fallback_enabled {
658-
return Err(format!("CDN metadata 获取失败,未启用自动回退: {}", e));
586+
info!("fallback 已启用,回退到 GitHub API");
659587
}
660-
661-
info!("fallback 已启用,回退到 GitHub API");
662588
}
589+
} else {
590+
info!("CDN 未启用,使用 GitHub API");
663591
}
664592

665593
let releases = self.fetch_github_releases().await?;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use log::info;
2+
use serde::{Deserialize, Serialize};
3+
4+
// 通用的 CDN Metadata 结构
5+
#[derive(Debug, Deserialize, Serialize, Clone)]
6+
pub struct MetadataRelease {
7+
pub version: String,
8+
pub display_name: String,
9+
pub published_at: String,
10+
pub download_url: String,
11+
pub github_url: String,
12+
pub file_name: String,
13+
pub size: u64,
14+
#[serde(default)]
15+
pub supported_platforms: Vec<String>,
16+
}
17+
18+
#[derive(Debug, Deserialize, Serialize)]
19+
pub struct Metadata {
20+
#[serde(default)]
21+
pub language: String,
22+
pub releases: Vec<MetadataRelease>,
23+
}
24+
25+
// 通用的 CDN 配置检查函数
26+
pub fn is_cdn_enabled() -> bool {
27+
use crate::config::get_app_config_internal;
28+
29+
get_app_config_internal()
30+
.ok()
31+
.and_then(|config| config.environment_mirror)
32+
.and_then(|mirror| mirror.enabled)
33+
.unwrap_or(false)
34+
}
35+
36+
// 通用的 fallback 配置检查函数
37+
pub fn is_fallback_enabled() -> bool {
38+
use crate::config::get_app_config_internal;
39+
40+
get_app_config_internal()
41+
.ok()
42+
.and_then(|config| config.environment_mirror)
43+
.and_then(|mirror| mirror.fallback_enabled)
44+
.unwrap_or(false)
45+
}
46+
47+
// 通用的从 CDN 获取 metadata 函数
48+
pub async fn fetch_metadata_from_cdn(language: &str) -> Result<Metadata, String> {
49+
use crate::config::get_app_config_internal;
50+
51+
let config = get_app_config_internal().map_err(|e| format!("读取配置失败: {}", e))?;
52+
53+
let cdn_enabled = config
54+
.environment_mirror
55+
.as_ref()
56+
.and_then(|m| m.enabled)
57+
.unwrap_or(false);
58+
59+
if !cdn_enabled {
60+
return Err("CDN 未启用".to_string());
61+
}
62+
63+
let base_url = config
64+
.environment_mirror
65+
.as_ref()
66+
.and_then(|m| m.base_url.as_ref())
67+
.ok_or("CDN 地址未配置")?;
68+
69+
let metadata_url = format!("{}/{}/metadata.json", base_url, language);
70+
info!("从 CDN 获取 {} metadata: {}", language, metadata_url);
71+
72+
let client = reqwest::Client::builder()
73+
.timeout(std::time::Duration::from_secs(30))
74+
.build()
75+
.map_err(|e| format!("创建 HTTP 客户端失败: {}", e))?;
76+
77+
let response = client
78+
.get(&metadata_url)
79+
.send()
80+
.await
81+
.map_err(|e| format!("请求 CDN metadata 失败: {}", e))?;
82+
83+
if !response.status().is_success() {
84+
return Err(format!("CDN 返回错误状态码: {}", response.status()));
85+
}
86+
87+
let metadata: Metadata = response
88+
.json()
89+
.await
90+
.map_err(|e| format!("解析 metadata.json 失败: {}", e))?;
91+
92+
info!("成功从 CDN 获取 {} 个版本", metadata.releases.len());
93+
Ok(metadata)
94+
}

src-tauri/src/env_providers/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod clojure;
2+
pub mod metadata;
23
pub mod scala;
34

45
pub use clojure::ClojureEnvironmentProvider;

src-tauri/src/env_providers/scala.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::metadata::{Metadata, fetch_metadata_from_cdn, is_cdn_enabled, is_fallback_enabled};
12
use crate::env_manager::{
23
DownloadStatus, EnvironmentProvider, EnvironmentVersion, download_with_fallback,
34
emit_download_progress,
@@ -250,6 +251,51 @@ impl ScalaEnvironmentProvider {
250251
false
251252
}
252253

254+
// 将 CDN metadata 转换为 EnvironmentVersion 列表
255+
fn parse_metadata_to_versions(
256+
&self,
257+
metadata: Metadata,
258+
) -> Result<Vec<EnvironmentVersion>, String> {
259+
let mut versions = Vec::new();
260+
261+
for release in metadata.releases {
262+
let version = release.version.clone();
263+
let is_installed = self.is_version_installed(&version);
264+
265+
// 如果已安装,查找实际的包含 bin 目录的路径
266+
let install_path = if is_installed {
267+
let version_dir = self.get_version_install_path(&version);
268+
let mut actual_path = version_dir.clone();
269+
270+
if let Ok(entries) = std::fs::read_dir(&version_dir) {
271+
for entry in entries.flatten() {
272+
let path = entry.path();
273+
if path.is_dir() && path.join("bin").exists() {
274+
actual_path = path;
275+
break;
276+
}
277+
}
278+
}
279+
280+
Some(actual_path.to_string_lossy().to_string())
281+
} else {
282+
None
283+
};
284+
285+
versions.push(EnvironmentVersion {
286+
version: version.clone(),
287+
download_url: release.download_url.clone(),
288+
fallback_url: Some(release.github_url.clone()),
289+
install_path,
290+
is_installed,
291+
size: Some(release.size),
292+
release_date: Some(release.published_at.clone()),
293+
});
294+
}
295+
296+
Ok(versions)
297+
}
298+
253299
// 下载文件并显示进度
254300
async fn download_file(
255301
&self,
@@ -464,6 +510,28 @@ impl EnvironmentProvider for ScalaEnvironmentProvider {
464510
}
465511

466512
async fn fetch_available_versions(&self) -> Result<Vec<EnvironmentVersion>, String> {
513+
// 检查 CDN 是否启用
514+
if is_cdn_enabled() {
515+
match fetch_metadata_from_cdn("scala").await {
516+
Ok(metadata) => {
517+
info!("使用 CDN metadata 获取版本列表");
518+
return self.parse_metadata_to_versions(metadata);
519+
}
520+
Err(e) => {
521+
warn!("CDN metadata 获取失败: {}", e);
522+
523+
// 检查是否启用 fallback
524+
if !is_fallback_enabled() {
525+
return Err(format!("CDN metadata 获取失败,未启用自动回退: {}", e));
526+
}
527+
528+
info!("fallback 已启用,回退到 GitHub API");
529+
}
530+
}
531+
} else {
532+
info!("CDN 未启用,使用 GitHub API");
533+
}
534+
467535
let releases = self.fetch_github_releases().await?;
468536
let pattern = Self::get_download_pattern();
469537

0 commit comments

Comments
 (0)