fn main() { download::start().unwrap(); }
#[cfg(any(docsrs, not(feature = "download")))]
mod download {
pub(crate) fn start() -> Result<(), ()> { Ok(()) }
}
#[cfg(feature = "download")]
mod download {
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use std::process::Command;
use std::str::FromStr;
use anyhow::Context;
use bitcoin_hashes::{sha256, Hash};
include!("src/versions.rs");
const GITHUB_URL: &str =
"https://github.com/RCasatta/electrsd/releases/download/electrs_releases";
fn get_expected_sha256(filename: &str) -> anyhow::Result<sha256::Hash> {
let file = File::open("sha256")?;
for line in BufReader::new(file).lines().map_while(Result::ok) {
let tokens: Vec<_> = line.split(" ").collect();
if tokens.len() == 2 && filename == tokens[1] {
return Ok(sha256::Hash::from_str(tokens[0]).unwrap());
}
}
panic!("no sha256 entry for {} in electrsd/sha256", filename);
}
pub(crate) fn start() -> anyhow::Result<()> {
if std::env::var_os("ELECTRSD_SKIP_DOWNLOAD").is_some() {
return Ok(());
}
let download_filename_without_extension = electrs_name();
let download_filename = format!("{}.zip", download_filename_without_extension);
let expected_hash = get_expected_sha256(&download_filename)?;
let out_dir = std::env::var_os("OUT_DIR").unwrap();
let electrs_exe_home = Path::new(&out_dir).join("electrs");
let destination_filename =
electrs_exe_home.join(&download_filename_without_extension).join("electrs");
if !destination_filename.exists() {
println!("filename:{} version:{} hash:{}", download_filename, VERSION, expected_hash);
let download_endpoint =
std::env::var("ELECTRSD_DOWNLOAD_ENDPOINT").unwrap_or(GITHUB_URL.to_string());
let url = format!("{}/{}", download_endpoint, download_filename);
let downloaded_bytes = bitreq::get(url.clone()).send()?.into_bytes();
let downloaded_hash = sha256::Hash::hash(&downloaded_bytes);
assert_eq!(expected_hash, downloaded_hash, "expected hash of {} is not matching", url);
let archive_path = Path::new(&out_dir).join(&download_filename);
std::fs::write(&archive_path, &downloaded_bytes)?;
let output = Command::new("unzip")
.arg("-p")
.arg(&archive_path)
.arg("electrs")
.output()
.context("failed to run unzip; install unzip and ensure it is in PATH")?;
anyhow::ensure!(
output.status.success(),
"unzip failed to extract {}: {}",
download_filename,
String::from_utf8_lossy(&output.stderr)
);
let parent = destination_filename.parent().unwrap();
std::fs::create_dir_all(parent)?;
std::fs::write(&destination_filename, output.stdout)?;
std::fs::set_permissions(
&destination_filename,
std::fs::Permissions::from_mode(0o755),
)?;
std::fs::remove_file(&archive_path)?;
}
Ok(())
}
}