github_bin_downloader/
ghapi.rs1use crate::sysinfo;
2use crate::utils;
3
4use crate::GBDResult;
5use reqwest::{StatusCode, Url};
6use serde_json::Value;
7use thiserror::Error;
8
9#[derive(Debug, Default)]
10pub struct RepoInfo {
11 user_name: String,
12 repo_name: String,
13 url: String,
14 releases_api_url: String,
15 pub releases: Vec<Release>,
16}
17
18#[derive(Clone, Debug, PartialEq)]
19pub struct Release {
20 pub name: String,
21 pub url: String,
22}
23
24impl Release {
25 pub async fn download_release(&self) -> GBDResult<()> {
27 let url = Url::parse(self.url.as_str())?;
28 println!("Downloading {} from {}", self.name, url);
29 utils::download_file_from_url(url, &self.name).await?;
30 Ok(())
31 }
32}
33
34impl ToString for Release {
35 fn to_string(&self) -> String {
36 self.name.to_string()
37 }
38}
39
40#[derive(Error, Debug)]
41pub enum GithubError {
42 #[error("Repo Not Found")]
43 NotFound(StatusCode),
44}
45
46impl RepoInfo {
47 pub async fn from_url(url: &str) -> GBDResult<Self> {
48 let mut url = url.to_string();
49 if !url.contains("https://") && !url.contains("http://") {
50 url = format!("https://{}", url);
51 }
52 if !url.contains("github") {
53 return Err(Box::new(GithubError::NotFound(StatusCode::NOT_IMPLEMENTED)));
54 }
55 let resp = reqwest::get(&url).await?;
56 if resp.status() == StatusCode::OK {
57 let path = resp.url().path();
58 let repoinfo_vec: Vec<&str> = path.split('/').collect();
59 let releases_api_url = format!(
60 "https://api.github.com/repos/{}/{}/releases",
61 repoinfo_vec[1].to_string(),
62 repoinfo_vec[2].to_string()
63 );
64 Ok(RepoInfo {
65 user_name: repoinfo_vec[1].to_string(),
66 repo_name: repoinfo_vec[2].to_string(),
67 url,
68 releases_api_url,
69 ..Default::default()
70 })
71 } else {
72 Err(Box::new(GithubError::NotFound(resp.status())))
73 }
74 }
75
76 pub async fn get_latest_release(&mut self) -> GBDResult<()> {
78 let client = reqwest::Client::builder()
79 .user_agent("github-bin-downloader")
80 .build()?;
81 let resp = client
82 .get(&self.releases_api_url)
83 .send()
84 .await?
85 .text()
86 .await?;
87 let repo: Value = serde_json::from_str(&resp)?;
88 let length = repo[0]["assets"]
89 .as_array()
90 .expect("Cannot convert to Array")
91 .len();
92 let mut releases: Vec<Release> = Vec::new();
93 for i in 0..length {
94 releases.push(Release {
95 name: utils::sanitize_str_to_string(&repo[0]["assets"][i]["name"]),
96 url: utils::sanitize_str_to_string(&repo[0]["assets"][i]["browser_download_url"]),
97 });
98 }
99 self.releases = releases;
100 Ok(())
101 }
102
103 pub async fn get_latest_stable_release(&mut self) -> GBDResult<()> {
105 let client = reqwest::Client::builder()
106 .user_agent("github-bin-downloader")
107 .build()?;
108 let resp = client
109 .get(&self.releases_api_url)
110 .send()
111 .await?
112 .text()
113 .await?;
114 let repo: Value = serde_json::from_str(&resp)?;
115 let length = repo.as_array().expect("Cannot convert to Array").len();
116 let mut releases: Vec<Release> = Vec::new();
117 for i in 0..length {
118 if !repo[i]["prerelease"]
119 .as_bool()
120 .expect("Cannot convert to bool")
121 {
122 let length = repo[i]["assets"]
123 .as_array()
124 .expect("Cannot convert to Array")
125 .len();
126 for j in 0..length {
127 releases.push(Release {
128 name: utils::sanitize_str_to_string(&repo[i]["assets"][j]["name"]),
129 url: utils::sanitize_str_to_string(
130 &repo[i]["assets"][j]["browser_download_url"],
131 ),
132 });
133 }
134 self.releases = releases;
135 return Ok(());
136 }
137 }
138 Ok(())
139 }
140
141 pub async fn search_releases_for_os(&self) -> GBDResult<Vec<Release>> {
143 let sys_info = sysinfo::SystemInfo::new();
144 let mut releases: Vec<Release> = Vec::new();
145 match sys_info.platform_os() {
146 sysinfo::PlatformOS::Darwin => {
147 sysinfo::APPLE.iter().for_each(|mac| {
148 self.releases.iter().for_each(|release| {
149 if release.name.to_lowercase().contains(mac) {
150 releases.push(release.clone());
151 }
152 });
153 });
154 }
155 sysinfo::PlatformOS::Linux => {
156 sysinfo::LINUX.iter().for_each(|linux| {
157 self.releases.iter().for_each(|release| {
158 if release.name.to_lowercase().contains(linux) {
159 releases.push(release.clone());
160 }
161 });
162 });
163 }
164 _ => {}
165 }
166 Ok(releases)
167 }
168
169 pub async fn search_releases_for_arch(&self) -> GBDResult<Vec<Release>> {
171 let sys_info = sysinfo::SystemInfo::new();
172 let mut releases: Vec<Release> = Vec::new();
173 match sys_info.platform_arch() {
174 sysinfo::PlatformArch::X8664 => {
175 sysinfo::AMD64.iter().for_each(|arch| {
176 self.releases.iter().for_each(|release| {
177 if release.name.contains(arch) {
178 releases.push(release.clone());
179 }
180 });
181 });
182 }
183 sysinfo::PlatformArch::Arm64 => {
184 sysinfo::ARM64.iter().for_each(|arch| {
185 self.releases.iter().for_each(|release| {
186 if release.name.contains(arch) {
187 releases.push(release.clone());
188 }
189 });
190 });
191 }
192 _ => {}
193 }
194 Ok(releases)
195 }
196}