soar_dl/
github.rs

1use serde::Deserialize;
2
3use crate::{
4    error::PlatformError,
5    platform::{Release, ReleaseAsset, ReleasePlatform},
6};
7
8pub struct Github;
9impl ReleasePlatform for Github {
10    const API_BASE_PRIMARY: &'static str = "https://api.github.com";
11
12    const API_BASE_PKGFORGE: &'static str = "https://api.gh.pkgforge.dev";
13
14    const TOKEN_ENV_VAR: &'static str = "GITHUB_TOKEN";
15
16    fn format_project_path(project: &str) -> Result<(String, String), PlatformError> {
17        match project.split_once('/') {
18            Some((owner, repo)) if !owner.trim().is_empty() && !repo.trim().is_empty() => {
19                Ok((owner.to_string(), repo.to_string()))
20            }
21            _ => Err(PlatformError::InvalidInput(format!(
22                "Github project '{}' must be in 'owner/repo' format",
23                project
24            ))),
25        }
26    }
27
28    fn format_api_path(project: &str, tag: Option<&str>) -> Result<String, PlatformError> {
29        let (owner, repo) = Self::format_project_path(project)?;
30        let base_path = format!("/repos/{}/{}/releases", owner, repo);
31        if let Some(tag) = tag {
32            Ok(format!("{}/tags/{}?per_page=100", base_path, tag))
33        } else {
34            Ok(format!("{}?per_page=100", base_path))
35        }
36    }
37}
38
39#[derive(Debug, Deserialize)]
40pub struct GithubRelease {
41    name: Option<String>,
42    tag_name: String,
43    prerelease: bool,
44    published_at: String,
45    assets: Vec<GithubAsset>,
46}
47
48impl Release<GithubAsset> for GithubRelease {
49    fn name(&self) -> &str {
50        self.name.as_deref().unwrap_or("")
51    }
52
53    fn tag_name(&self) -> &str {
54        &self.tag_name
55    }
56
57    fn is_prerelease(&self) -> bool {
58        self.prerelease
59    }
60
61    fn published_at(&self) -> &str {
62        &self.published_at
63    }
64
65    fn assets(&self) -> Vec<GithubAsset> {
66        self.assets.clone()
67    }
68}
69
70#[derive(Clone, Debug, Deserialize)]
71pub struct GithubAsset {
72    pub name: String,
73    pub size: u64,
74    pub browser_download_url: String,
75}
76
77impl ReleaseAsset for GithubAsset {
78    fn name(&self) -> &str {
79        &self.name
80    }
81
82    fn size(&self) -> Option<u64> {
83        Some(self.size)
84    }
85
86    fn download_url(&self) -> &str {
87        &self.browser_download_url
88    }
89}