avalanche_installer/
github.rs1use std::{
2 io::{self, Error, ErrorKind},
3 time::Duration,
4};
5
6use reqwest::ClientBuilder;
7use serde::{Deserialize, Serialize};
8
9pub async fn fetch_latest_release(org: &str, repo: &str) -> io::Result<ReleaseResponse> {
12 let ep = format!(
13 "https://api.github.com/repos/{}/{}/releases/latest",
14 org, repo
15 );
16 log::info!("fetching {}", ep);
17
18 let cli = ClientBuilder::new()
19 .user_agent(env!("CARGO_PKG_NAME"))
20 .danger_accept_invalid_certs(true)
21 .timeout(Duration::from_secs(15))
22 .connection_verbose(true)
23 .build()
24 .map_err(|e| {
25 Error::new(
26 ErrorKind::Other,
27 format!("failed ClientBuilder build {}", e),
28 )
29 })?;
30 let resp =
31 cli.get(&ep).send().await.map_err(|e| {
32 Error::new(ErrorKind::Other, format!("failed ClientBuilder send {}", e))
33 })?;
34 let out = resp
35 .bytes()
36 .await
37 .map_err(|e| Error::new(ErrorKind::Other, format!("failed ClientBuilder send {}", e)))?;
38 let out: Vec<u8> = out.into();
39
40 let resp: ReleaseResponse = match serde_json::from_slice(&out) {
41 Ok(p) => p,
42 Err(e) => {
43 return Err(Error::new(
44 ErrorKind::Other,
45 format!("failed to decode {}", e),
46 ));
47 }
48 };
49 Ok(resp)
50}
51
52#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
54#[serde(rename_all = "snake_case")]
55pub struct ReleaseResponse {
56 pub tag_name: Option<String>,
58 pub assets: Option<Vec<Asset>>,
60
61 #[serde(default)]
62 pub prerelease: bool,
63}
64
65impl Default for ReleaseResponse {
66 fn default() -> Self {
67 Self::default()
68 }
69}
70
71impl ReleaseResponse {
72 pub fn default() -> Self {
73 Self {
74 tag_name: None,
75 assets: None,
76 prerelease: false,
77 }
78 }
79}
80
81#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
83#[serde(rename_all = "snake_case")]
84pub struct Asset {
85 pub name: String,
86 pub browser_download_url: String,
87}