Skip to content
Merged
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
46 changes: 34 additions & 12 deletions src/services/curseforge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,21 +306,11 @@ impl CurseforgeService {
mods.push(doc);
}

// empty 则直接返回 { "data": [] }
if mods.is_empty() {
return Err(ServiceError::NotFound {
resource: String::from("Mods"),
detail: Some(format!(
"No mods found for the provided modIds: {:?}",
mod_ids
)),
});
}

// 检查是否有未找到的 mod_id
let found_mod_ids: Vec<i32> = mods.iter().map(|m| m.id).collect();
let not_found_mod_ids: Vec<i32> = mod_ids
.into_iter()
.iter()
.copied()
.filter(|id| !found_mod_ids.contains(id))
.collect();
if !not_found_mod_ids.is_empty() {
Expand All @@ -333,6 +323,38 @@ impl CurseforgeService {
log::trace!("All Mods have been found in the database.");
}

/*
curl -i -X 'POST' \
'https://api.curseforge.com/v1/mods' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'x-api-key: $API_KEY' \
-d '{
"filterPcOnly": true,
"modIds": [
238222112
]
}'
HTTP/2 404
content-length: 0
date: Sat, 12 Sep 2026 07:06:03 GMT
x-cache: Error from cloudfront
via: 1.1 715cc2fe99ad4f311de46e74c166c5a2.cloudfront.net (CloudFront)
x-amz-cf-pop: LOS50-P4
x-amz-cf-id: EGanUHlrFZiDD8YG6hWQpedqhiWQ30pKnB7DX8CBBNyTsyixGDDjNQ==
*/
// 不会返回 Body,可以任意填写
// 但是必须返回 404,不能返回 200
if mods.is_empty() {
return Err(ServiceError::NotFound {
resource: String::from("Mods"),
detail: Some(format!(
"No mods found for the provided modIds: {:?}",
mod_ids
)),
});
}

let response_mods = mods.into_iter().map(|m| m.into()).collect();
Ok(ModsResponse {
data: response_mods,
Expand Down
47 changes: 42 additions & 5 deletions src/services/modrinth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ impl ModrinthService {
params.push(("index", i.to_string()));
}

// 在此处要打断 4xx/5xx 错误,返回 ServiceError::ExternalServiceError,以免被缓存
let response = client
.get(api_url)
.query(&params)
Expand All @@ -376,16 +377,34 @@ impl ModrinthService {
.map_err(|e| ServiceError::ExternalServiceError {
service: String::from("Modrinth API"),
message: format!("Failed to send request: {}", e),
})?
.error_for_status()
.map_err(|e| ServiceError::ExternalServiceError {
service: String::from("Modrinth API"),
message: format!("Upstream HTTP error: {}", e),
})?;

let status = response.status();
// 在此处要打断 4xx/5xx 错误,返回 ServiceError::ExternalServiceError,以免被缓存
if let Err(e) = response.error_for_status_ref() {
let error_body = response
.text()
.await
.unwrap_or_else(|_| String::from("<failed to read body>"));
return Err(ServiceError::ExternalServiceError {
service: String::from("Modrinth API"),
message: format!("Upstream HTTP error: {}, body: {}", e, error_body),
});
}

let status: reqwest::StatusCode = response.status();
let bytes = response
.bytes()
.await
.map_err(|e| ServiceError::ExternalServiceError {
service: String::from("Modrinth API"),
message: format!("Failed to read response body: {}", e),
})?;

let search_result = serde_json::from_slice(&bytes).map_err(|e| {
ServiceError::UnexpectedError(format!(
"Failed to parse JSON: {}, text: {}",
Expand Down Expand Up @@ -925,14 +944,32 @@ impl ModrinthService {
// 创建哈希值到版本的映射
let mut result: HashMap<String, Version> = HashMap::new();

// 用 HashSet 来优化查找速度,避免 Vec contains O(n) 查找
let requested_hashes_set: std::collections::HashSet<&str> =
hashes.iter().map(|s| s.as_str()).collect();

for version in versions {
if let Some(first_file) = version.files.first() {
// 此处导致只有是第一个文件的哈希值会被映射到版本,其他文件的哈希值不会被映射
// if let Some(first_file) = version.files.first() {
// let hash_value = match algorithm.as_str() {
// "sha1" => &first_file.hashes.sha1,
// "sha512" => &first_file.hashes.sha512,
// _ => continue,
// };
// result.insert(hash_value.clone(), version);
// }

// 遍历版本的所有文件,找到匹配的哈希值
for file in &version.files {
let hash_value = match algorithm.as_str() {
"sha1" => &first_file.hashes.sha1,
"sha512" => &first_file.hashes.sha512,
"sha1" => &file.hashes.sha1,
"sha512" => &file.hashes.sha512,
_ => continue,
};
result.insert(hash_value.clone(), version);
// 只有客户端查询列表中包含的 hash,才插入到结果中
if requested_hashes_set.contains(hash_value.as_str()) {
result.insert(hash_value.clone(), version.clone());
}
}
}

Expand Down
Loading