1use anyhow::{anyhow, Result};
2use std::env;
3
4#[derive(Debug, Clone)]
5pub enum Os {
6 Linux,
7 MacOs,
8 Windows,
9}
10
11#[derive(Debug, Clone)]
12pub enum Arch {
13 X86_64,
14 Aarch64,
15}
16
17pub struct MongoUrl {
18 pub url: String,
19 pub filename: String,
20}
21
22pub fn get_os() -> Result<Os> {
23 match env::consts::OS {
24 "linux" => Ok(Os::Linux),
25 "macos" => Ok(Os::MacOs),
26 "windows" => Ok(Os::Windows),
27 os => Err(anyhow!("Unsupported OS: {}", os)),
28 }
29}
30
31pub fn get_arch() -> Result<Arch> {
32 match env::consts::ARCH {
33 "x86_64" => Ok(Arch::X86_64),
34 "aarch64" => Ok(Arch::Aarch64),
35 arch => Err(anyhow!("Unsupported Architecture: {}", arch)),
36 }
37}
38
39pub fn get_download_url(version: &str) -> Result<MongoUrl> {
40 let os = get_os()?;
41 let arch = get_arch()?;
42
43 let (_platform, package_format) = match (&os, &arch) {
44 (Os::Linux, Arch::X86_64) => ("linux-x86_64", "tgz"),
45 (Os::Linux, Arch::Aarch64) => ("linux-aarch64", "tgz"),
46 (Os::MacOs, Arch::X86_64) => ("macos-x86_64", "tgz"),
47 (Os::MacOs, Arch::Aarch64) => ("macos-aarch64", "tgz"),
48 (Os::Windows, Arch::X86_64) => ("windows-x86_64", "zip"),
49 _ => return Err(anyhow!("Unsupported OS/Arch combination")),
50 };
51
52 let base_url = "https://fastdl.mongodb.org";
66
67 let _filename = match os {
68 Os::Linux => format!("mongodb-linux-{}-{}.{}", "x86_64-ubuntu2204", version, package_format), Os::MacOs => format!("mongodb-macos-{}-{}.{}", "x86_64", version, package_format), Os::Windows => format!("mongodb-windows-x86_64-{}.{}", version, package_format),
71 };
72
73 let url = match (&os, &arch) {
75 (Os::Linux, Arch::X86_64) => format!("{}/linux/mongodb-linux-x86_64-ubuntu2204-{}.tgz", base_url, version),
76 (Os::Linux, Arch::Aarch64) => format!("{}/linux/mongodb-linux-aarch64-ubuntu2204-{}.tgz", base_url, version),
77 (Os::MacOs, Arch::X86_64) => format!("{}/osx/mongodb-macos-x86_64-{}.tgz", base_url, version),
78 (Os::MacOs, Arch::Aarch64) => format!("{}/osx/mongodb-macos-aarch64-{}.tgz", base_url, version),
79 (Os::Windows, Arch::X86_64) => format!("{}/windows/mongodb-windows-x86_64-{}.zip", base_url, version),
80 _ => return Err(anyhow!("Unsupported OS/Arch combination")),
81 };
82
83 let filename = url.split('/').last().unwrap().to_string();
84
85 Ok(MongoUrl {
86 url,
87 filename,
88 })
89}
90
91
92pub struct DownloadProgress {
93 pub downloaded: u64,
94 pub total: Option<u64>,
95 pub percentage: Option<f32>,
96}
97
98pub async fn download_file(url: &str, destination: &std::path::Path) -> Result<()> {
99 download_file_with_callback(url, destination, |_| {}).await
100}
101
102pub async fn download_file_with_callback<F>(
103 url: &str,
104 destination: &std::path::Path,
105 mut callback: F,
106) -> Result<()>
107where
108 F: FnMut(DownloadProgress),
109{
110 use std::io::Write;
111 use std::fs::File;
112
113 let response = reqwest::get(url).await?;
114 let total = response.content_length();
115
116 let mut part_path = destination.to_path_buf();
117 part_path.set_extension("part");
118
119 let mut file = File::create(&part_path)?;
120 let mut downloaded: u64 = 0;
121
122 let mut stream = response;
123 while let Some(chunk) = stream.chunk().await? {
124 file.write_all(&chunk)?;
125 downloaded += chunk.len() as u64;
126
127 let percentage = total.map(|t| (downloaded as f32 / t as f32) * 100.0);
128 callback(DownloadProgress {
129 downloaded,
130 total,
131 percentage,
132 });
133 }
134
135 std::fs::rename(part_path, destination)?;
136
137 Ok(())
138}