Add windows support to monero rpc installer

pull/253/head
rishflab 3 years ago
parent 27df9128be
commit bcdde021eb

66
Cargo.lock generated

@ -1,5 +1,11 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "aead"
version = "0.3.2"
@ -121,7 +127,7 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b72c1f1154e234325b50864a349b9c8e56939e266a4c307c0f159812df2f9537"
dependencies = [
"bzip2",
"bzip2 0.4.2",
"futures-core",
"memchr",
"pin-project-lite",
@ -498,6 +504,16 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
[[package]]
name = "bzip2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
dependencies = [
"bzip2-sys",
"libc",
]
[[package]]
name = "bzip2"
version = "0.4.2"
@ -1068,6 +1084,18 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "flate2"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42"
dependencies = [
"cfg-if 0.1.10",
"crc32fast",
"libc",
"miniz_oxide",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -1979,6 +2007,15 @@ dependencies = [
"serde",
]
[[package]]
name = "miniz_oxide"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
dependencies = [
"adler32",
]
[[package]]
name = "mio"
version = "0.7.7"
@ -3580,7 +3617,7 @@ dependencies = [
"tempfile",
"testcontainers 0.12.0",
"thiserror",
"time",
"time 0.2.24",
"tokio",
"tokio-tar",
"tokio-tungstenite",
@ -3593,6 +3630,7 @@ dependencies = [
"url",
"uuid",
"void",
"zip",
]
[[package]]
@ -3722,6 +3760,16 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
"libc",
"winapi 0.3.9",
]
[[package]]
name = "time"
version = "0.2.24"
@ -4452,3 +4500,17 @@ dependencies = [
"syn",
"synstructure",
]
[[package]]
name = "zip"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a8977234acab718eb2820494b2f96cbb16004c19dddf88b7445b27381450997"
dependencies = [
"byteorder",
"bzip2 0.3.3",
"crc32fast",
"flate2",
"thiserror",
"time 0.1.43",
]

@ -51,7 +51,6 @@ strum = { version = "0.20", features = ["derive"] }
thiserror = "1"
time = "0.2"
tokio = { version = "1.0", features = ["rt-multi-thread", "time", "macros", "sync", "process", "fs"] }
tokio-tar = { path = "../tokio-tar" }
tokio-tungstenite = { version = "0.13", features = [ "tls" ] }
tokio-util = { version = "0.6.3", features = ["io"] }
toml = "0.5"
@ -63,6 +62,12 @@ url = { version = "2.1", features = ["serde"] }
uuid = { version = "0.8", features = ["serde", "v4"] }
void = "1"
[target.'cfg(not(windows))'.dependencies]
tokio-tar = { path = "../tokio-tar" }
[target.'cfg(windows)'.dependencies]
zip = "0.5"
[dev-dependencies]
bitcoin-harness = { git = "https://github.com/coblox/bitcoin-harness-rs" }
get-port = "3"

@ -1,6 +1,5 @@
use ::monero::Network;
use anyhow::{bail, Context, Result};
use async_compression::tokio::bufread::BzDecoder;
use anyhow::{Context, Result};
use big_bytes::BigByte;
use futures::{StreamExt, TryStreamExt};
use reqwest::{header::CONTENT_LENGTH, Url};
@ -14,23 +13,29 @@ use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
process::{Child, Command},
};
use tokio_tar::Archive;
use tokio_util::{
codec::{BytesCodec, FramedRead},
io::StreamReader,
};
#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
compile_error!("unsupported operating system");
#[cfg(target_os = "macos")]
const DOWNLOAD_URL: &str = "http://downloads.getmonero.org/cli/monero-mac-x64-v0.17.1.9.tar.bz2";
#[cfg(target_os = "linux")]
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-linux-x64-v0.17.1.9.tar.bz2";
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
compile_error!("unsupported operating system");
#[cfg(target_os = "windows")]
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-win-x64-v0.17.1.9.zip";
#[cfg(any(target_os = "macos", target_os = "linux"))]
const PACKED_FILE: &str = "monero-wallet-rpc";
#[cfg(target_os = "windows")]
const PACKED_FILE: &str = "monero-wallet-rpc.exe";
#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("monero wallet rpc executable not found in downloaded archive")]
pub struct ExecutableNotFoundInArchive;
@ -63,8 +68,8 @@ impl WalletRpc {
working_dir: working_dir.to_path_buf(),
};
if monero_wallet_rpc.tar_path().exists() {
remove_file(monero_wallet_rpc.tar_path()).await?;
if monero_wallet_rpc.archive_path().exists() {
remove_file(monero_wallet_rpc.archive_path()).await?;
}
if !monero_wallet_rpc.exec_path().exists() {
@ -73,7 +78,7 @@ impl WalletRpc {
.read(true)
.write(true)
.create_new(true)
.open(monero_wallet_rpc.tar_path())
.open(monero_wallet_rpc.archive_path())
.await?;
let response = reqwest::get(DOWNLOAD_URL).await?;
@ -92,48 +97,28 @@ impl WalletRpc {
.bytes_stream()
.map_err(|err| std::io::Error::new(ErrorKind::Other, err));
#[cfg(not(target_os = "windows"))]
let mut stream = FramedRead::new(
BzDecoder::new(StreamReader::new(byte_stream)),
async_compression::tokio::bufread::BzDecoder::new(StreamReader::new(byte_stream)),
BytesCodec::new(),
)
.map_ok(|bytes| bytes.freeze());
#[cfg(target_os = "windows")]
let mut stream = FramedRead::new(StreamReader::new(byte_stream), BytesCodec::new())
.map_ok(|bytes| bytes.freeze());
while let Some(chunk) = stream.next().await {
file.write(&chunk?).await?;
}
file.flush().await?;
let mut options = OpenOptions::new();
let file = options
.read(true)
.open(monero_wallet_rpc.tar_path())
.await?;
let mut ar = Archive::new(file);
let mut entries = ar.entries()?;
loop {
match entries.next().await {
Some(file) => {
let mut f = file?;
if f.path()?
.to_str()
.context("Could not find convert path to str in tar ball")?
.contains(PACKED_FILE)
{
f.unpack(monero_wallet_rpc.exec_path()).await?;
break;
}
}
None => bail!(ExecutableNotFoundInArchive),
}
}
remove_file(monero_wallet_rpc.tar_path()).await?;
Self::extract_archive(&monero_wallet_rpc).await?;
}
Ok(monero_wallet_rpc)
}
pub async fn run(&self, network: Network, daemon_host: &str) -> Result<WalletRpcProcess> {
let port = tokio::net::TcpListener::bind("127.0.0.1:0")
.await?
@ -178,11 +163,78 @@ impl WalletRpc {
})
}
fn tar_path(&self) -> PathBuf {
self.working_dir.join("monero-cli-wallet.tar")
fn archive_path(&self) -> PathBuf {
self.working_dir.join("monero-cli-wallet.archive")
}
fn exec_path(&self) -> PathBuf {
self.working_dir.join(PACKED_FILE)
}
#[cfg(not(target_os = "windows"))]
async fn extract_archive(monero_wallet_rpc: &Self) -> Result<()> {
use anyhow::bail;
use tokio_tar::Archive;
let mut options = OpenOptions::new();
let file = options
.read(true)
.open(monero_wallet_rpc.archive_path())
.await?;
let mut ar = Archive::new(file);
let mut entries = ar.entries()?;
loop {
match entries.next().await {
Some(file) => {
let mut f = file?;
if f.path()?
.to_str()
.context("Could not find convert path to str in tar ball")?
.contains(PACKED_FILE)
{
f.unpack(monero_wallet_rpc.exec_path()).await?;
break;
}
}
None => bail!(ExecutableNotFoundInArchive),
}
}
remove_file(monero_wallet_rpc.archive_path()).await?;
Ok(())
}
#[cfg(target_os = "windows")]
async fn extract_archive(monero_wallet_rpc: &Self) -> Result<()> {
use std::fs::File;
use tokio::task::JoinHandle;
use zip::ZipArchive;
let archive_path = monero_wallet_rpc.archive_path();
let exec_path = monero_wallet_rpc.exec_path();
let extract: JoinHandle<Result<()>> = tokio::task::spawn_blocking(|| {
let file = File::open(archive_path)?;
let mut zip = ZipArchive::new(file)?;
let name = zip
.file_names()
.find(|name| name.contains(PACKED_FILE))
.context(ExecutableNotFoundInArchive)?
.to_string();
let mut rpc = zip.by_name(&name)?;
let mut file = File::create(exec_path)?;
std::io::copy(&mut rpc, &mut file)?;
Ok(())
});
extract.await??;
remove_file(monero_wallet_rpc.archive_path()).await?;
Ok(())
}
}

Loading…
Cancel
Save