mirror of
https://github.com/yuzu-emu/liftinstall.git
synced 2025-11-05 14:05:03 +00:00
123 lines
3.6 KiB
Rust
123 lines
3.6 KiB
Rust
//! github/mod.rs
|
|
//!
|
|
//! Contains the Github API implementation of a release source.
|
|
|
|
use reqwest::header::USER_AGENT;
|
|
use reqwest::StatusCode;
|
|
|
|
use serde_json;
|
|
|
|
use sources::types::*;
|
|
|
|
use http::build_client;
|
|
|
|
pub struct GithubReleases {}
|
|
|
|
/// The configuration for this release.
|
|
#[derive(Serialize, Deserialize)]
|
|
struct GithubConfig {
|
|
repo: String,
|
|
}
|
|
|
|
impl GithubReleases {
|
|
pub fn new() -> Self {
|
|
GithubReleases {}
|
|
}
|
|
}
|
|
|
|
impl ReleaseSource for GithubReleases {
|
|
fn get_current_releases(&self, config: &TomlValue) -> Result<Vec<Release>, String> {
|
|
// Reparse our Config as strongly typed
|
|
let config: GithubConfig = match config.clone().try_into() {
|
|
Ok(v) => v,
|
|
Err(v) => return Err(format!("Failed to parse release config: {:?}", v)),
|
|
};
|
|
|
|
let mut results: Vec<Release> = Vec::new();
|
|
|
|
// Build the HTTP client up
|
|
let client = build_client()?;
|
|
let mut response = client
|
|
.get(&format!(
|
|
"https://api.github.com/repos/{}/releases",
|
|
config.repo
|
|
))
|
|
.header(USER_AGENT, "liftinstall (j-selby)")
|
|
.send()
|
|
.map_err(|x| format!("Error while sending HTTP request: {:?}", x))?;
|
|
|
|
match response.status() {
|
|
StatusCode::OK => {}
|
|
StatusCode::FORBIDDEN => {
|
|
return Err(
|
|
"GitHub is rate limiting you. Try moving to a internet connection \
|
|
that isn't shared, and/or disabling VPNs."
|
|
.to_string(),
|
|
);
|
|
}
|
|
_ => {
|
|
return Err(format!("Bad status code: {:?}.", response.status()));
|
|
}
|
|
}
|
|
|
|
let body = response
|
|
.text()
|
|
.map_err(|x| format!("Failed to decode HTTP response body: {:?}", x))?;
|
|
|
|
let result: serde_json::Value = serde_json::from_str(&body)
|
|
.map_err(|x| format!("Failed to parse response: {:?}", x))?;
|
|
|
|
let result: &Vec<serde_json::Value> = result
|
|
.as_array()
|
|
.ok_or_else(|| "Response was not an array!".to_string())?;
|
|
|
|
// Parse JSON from server
|
|
for entry in result.iter() {
|
|
let mut files = Vec::new();
|
|
|
|
let id: u64 = match entry["id"].as_u64() {
|
|
Some(v) => v,
|
|
None => return Err("JSON payload missing information about ID".to_string()),
|
|
};
|
|
|
|
let assets = match entry["assets"].as_array() {
|
|
Some(v) => v,
|
|
None => return Err("JSON payload not an array".to_string()),
|
|
};
|
|
|
|
for asset in assets.iter() {
|
|
let string = match asset["name"].as_str() {
|
|
Some(v) => v,
|
|
None => {
|
|
return Err(
|
|
"JSON payload missing information about release name".to_string()
|
|
);
|
|
}
|
|
};
|
|
|
|
let url = match asset["browser_download_url"].as_str() {
|
|
Some(v) => v,
|
|
None => {
|
|
return Err(
|
|
"JSON payload missing information about release URL".to_string()
|
|
);
|
|
}
|
|
};
|
|
|
|
files.push(File {
|
|
name: string.to_string(),
|
|
url: url.to_string(),
|
|
requires_authorization: false,
|
|
});
|
|
}
|
|
|
|
results.push(Release {
|
|
version: Version::new_number(id),
|
|
files,
|
|
});
|
|
}
|
|
|
|
Ok(results)
|
|
}
|
|
}
|