Skip to content
This repository was archived by the owner on Oct 2, 2025. It is now read-only.

Commit db2ce1c

Browse files
committed
fetch directly using tag api if tag is provided
1 parent e5620c0 commit db2ce1c

File tree

6 files changed

+49
-19
lines changed

6 files changed

+49
-19
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "soar-dl"
3-
version = "0.3.5"
3+
version = "0.4.0"
44
authors = ["Rabindra Dhakal <[email protected]>"]
55
description = "A fast download manager"
66
license = "MIT"
@@ -25,6 +25,7 @@ indicatif = { version = "0.17.9", optional = true }
2525
regex = { version = "1.11.1", default-features = false, features = ["std", "unicode-case", "unicode-perl"] }
2626
reqwest = { version = "0.12.9", default-features = false, features = ["rustls-tls", "stream", "http2", "blocking", "json"] }
2727
serde = { version = "1.0.215", features = ["derive"] }
28+
serde_json = "1.0.139"
2829
tokio = { version = "1.41.1", features = ["macros", "rt-multi-thread"] }
2930
url = "2.5.4"
3031

src/bin/soar-dl/download_manager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl DownloadManager {
8080
};
8181

8282
let options = self.create_platform_options(tag.map(String::from));
83-
let releases = handler.fetch_releases::<R>(project).await?;
83+
let releases = handler.fetch_releases::<R>(project, tag).await?;
8484
let assets = handler.filter_releases(&releases, &options).await?;
8585

8686
let selected_asset = self.select_asset(&assets)?;

src/github.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,16 @@ impl ReleasePlatform for Github {
2525
}
2626
}
2727

28-
fn format_api_path(project: &str) -> Result<String, PlatformError> {
28+
fn format_api_path(project: &str, tag: Option<&str>) -> Result<String, PlatformError> {
2929
let (owner, repo) = Self::format_project_path(project)?;
30-
Ok(format!("/repos/{}/{}/releases?per_page=100", owner, repo))
30+
if let Some(tag) = tag {
31+
Ok(format!(
32+
"/repos/{}/{}/releases/tags/{}?per_page=100",
33+
owner, repo, tag
34+
))
35+
} else {
36+
Ok(format!("/repos/{}/{}/releases?per_page=100", owner, repo))
37+
}
3138
}
3239
}
3340

src/gitlab.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@ impl ReleasePlatform for Gitlab {
2424
}
2525
}
2626

27-
fn format_api_path(project: &str) -> Result<String, PlatformError> {
28-
if project.chars().all(|c| c.is_numeric()) {
29-
Ok(format!("/api/v4/projects/{}/releases", project))
27+
fn format_api_path(project: &str, tag: Option<&str>) -> Result<String, PlatformError> {
28+
let encoded_path = project.replace('/', "%2F");
29+
if let Some(tag) = tag {
30+
Ok(format!(
31+
"/api/v4/projects/{}/releases/{}",
32+
encoded_path, tag
33+
))
3034
} else {
31-
let encoded_path = project.replace('/', "%2F");
3235
Ok(format!("/api/v4/projects/{}/releases", encoded_path))
3336
}
3437
}

src/platform.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
use regex::Regex;
77
use reqwest::header::{HeaderMap, AUTHORIZATION, USER_AGENT};
88
use serde::Deserialize;
9+
use serde_json::Value;
910
use url::Url;
1011

1112
use crate::{
@@ -89,7 +90,7 @@ pub trait ReleasePlatform {
8990
const TOKEN_ENV_VAR: &'static str;
9091

9192
fn format_project_path(project: &str) -> Result<(String, String), PlatformError>;
92-
fn format_api_path(project: &str) -> Result<String, PlatformError>;
93+
fn format_api_path(project: &str, tag: Option<&str>) -> Result<String, PlatformError>;
9394
}
9495

9596
pub trait ReleaseAsset {
@@ -137,13 +138,14 @@ impl<P: ReleasePlatform> ReleaseHandler<P> {
137138
&self,
138139
api_type: &ApiType,
139140
project: &str,
141+
tag: Option<&str>,
140142
) -> Result<reqwest::Response, PlatformError> {
141143
let base_url = match api_type {
142144
ApiType::PkgForge => P::API_BASE_PKGFORGE,
143145
ApiType::Primary => P::API_BASE_PRIMARY,
144146
};
145147

146-
let api_path = P::format_api_path(project)?;
148+
let api_path = P::format_api_path(project, tag)?;
147149
let url = format!("{}{}", base_url, api_path);
148150

149151
let mut headers = HeaderMap::new();
@@ -164,15 +166,19 @@ impl<P: ReleasePlatform> ReleaseHandler<P> {
164166
.map_err(|err| DownloadError::NetworkError { source: err })?)
165167
}
166168

167-
pub async fn fetch_releases<R>(&self, project: &str) -> Result<Vec<R>, PlatformError>
169+
pub async fn fetch_releases<R>(
170+
&self,
171+
project: &str,
172+
tag: Option<&str>,
173+
) -> Result<Vec<R>, PlatformError>
168174
where
169175
R: for<'de> Deserialize<'de>,
170176
{
171-
let response = match self.call_api(&ApiType::PkgForge, project).await {
177+
let response = match self.call_api(&ApiType::PkgForge, project, tag).await {
172178
Ok(resp) => {
173179
let status = resp.status();
174180
if should_fallback(status) {
175-
self.call_api(&ApiType::Primary, project).await?
181+
self.call_api(&ApiType::Primary, project, tag).await?
176182
} else {
177183
resp
178184
}
@@ -188,10 +194,22 @@ impl<P: ReleasePlatform> ReleaseHandler<P> {
188194
.into());
189195
}
190196

191-
response
197+
let value: Value = response
192198
.json()
193199
.await
194-
.map_err(|_| PlatformError::InvalidResponse)
200+
.map_err(|_| PlatformError::InvalidResponse)?;
201+
202+
match value {
203+
Value::Array(_) => {
204+
serde_json::from_value(value).map_err(|_| PlatformError::InvalidResponse)
205+
}
206+
Value::Object(_) => {
207+
let single: R =
208+
serde_json::from_value(value).map_err(|_| PlatformError::InvalidResponse)?;
209+
Ok(vec![single])
210+
}
211+
_ => Err(PlatformError::InvalidResponse),
212+
}
195213
}
196214

197215
pub async fn filter_releases<R, A>(

0 commit comments

Comments
 (0)