blueprint_manager/sources/
github.rs1use crate::gadget::native::get_gadget_binary;
2use crate::sdk;
3use crate::sdk::utils::{
4 get_download_url, hash_bytes_to_hex, is_windows, msg_to_error, valid_file_exists,
5};
6use crate::sources::BinarySourceFetcher;
7use async_trait::async_trait;
8use color_eyre::eyre::OptionExt;
9use gadget_sdk::{error, info};
10use std::path::PathBuf;
11use tangle_subxt::tangle_testnet_runtime::api::runtime_types::tangle_primitives::services::GithubFetcher;
12use tokio::io::AsyncWriteExt;
13
14pub struct GithubBinaryFetcher {
15 pub fetcher: GithubFetcher,
16 pub blueprint_id: u64,
17 pub gadget_name: String,
18}
19
20#[async_trait]
21impl BinarySourceFetcher for GithubBinaryFetcher {
22 async fn get_binary(&self) -> color_eyre::Result<PathBuf> {
23 let relevant_binary = get_gadget_binary(&self.fetcher.binaries.0)
24 .ok_or_eyre("Unable to find matching binary")?;
25 let expected_hash = sdk::utils::slice_32_to_sha_hex_string(relevant_binary.sha256);
26 let current_dir = std::env::current_dir()?;
27 let mut binary_download_path =
28 format!("{}/protocol-{:?}", current_dir.display(), self.fetcher.tag);
29
30 if is_windows() {
31 binary_download_path += ".exe"
32 }
33
34 info!("Downloading to {binary_download_path}");
35
36 let retrieved_hash = if !valid_file_exists(&binary_download_path, &expected_hash).await {
38 let url = get_download_url(relevant_binary, &self.fetcher);
39
40 let download = reqwest::get(&url)
41 .await
42 .map_err(|err| msg_to_error(err.to_string()))?
43 .bytes()
44 .await
45 .map_err(|err| msg_to_error(err.to_string()))?;
46 let retrieved_hash = hash_bytes_to_hex(&download);
47
48 let mut file = tokio::fs::File::create(&binary_download_path).await?;
50 file.write_all(&download).await?;
51 file.flush().await?;
52 Some(retrieved_hash)
53 } else {
54 None
55 };
56
57 if let Some(retrieved_hash) = retrieved_hash {
58 if retrieved_hash.trim() != expected_hash.trim() {
59 error!(
60 "Binary hash {} mismatched expected hash of {} for protocol: {}",
61 retrieved_hash, expected_hash, self.gadget_name
62 );
63 return Ok(PathBuf::from(binary_download_path));
64 }
65 }
66
67 Err(color_eyre::Report::msg(
68 "The hash of the downloaded binary did not match",
69 ))
70 }
71
72 fn blueprint_id(&self) -> u64 {
73 self.blueprint_id
74 }
75
76 fn name(&self) -> String {
77 self.gadget_name.clone()
78 }
79}