use crate::utils::parse_header_hashmap;
use fast_down_ffi::{Proxy, WriteMethod};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use slint::ToSharedString;
use std::{
collections::{HashMap, HashSet},
net::IpAddr,
path::PathBuf,
time::Duration,
};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct DownloadConfig {
pub save_dir: PathBuf,
pub file_name: String,
pub threads: usize,
pub proxy: Proxy<String>,
pub headers: HashMap<String, String>,
pub min_chunk_size: u64,
pub write_buffer_size: usize,
pub write_queue_cap: usize,
pub retry_gap: Duration,
pub pull_timeout: Duration,
pub accept_invalid_certs: bool,
pub accept_invalid_hostnames: bool,
pub local_address: Vec<IpAddr>,
pub max_speculative: usize,
pub write_method: WriteMethod,
pub retry_times: usize,
pub chunk_window: u64,
pub pre_allocate: bool,
pub parse_filename: bool,
}
impl Default for DownloadConfig {
fn default() -> Self {
Self {
save_dir: dirs::download_dir().unwrap_or_default(),
file_name: String::new(),
threads: 32,
proxy: Proxy::System,
headers: HashMap::new(),
min_chunk_size: 500 * 1024,
write_buffer_size: 16 * 1024 * 1024,
write_queue_cap: 10240,
retry_gap: Duration::from_millis(500),
pull_timeout: Duration::from_secs(5),
accept_invalid_certs: false,
accept_invalid_hostnames: false,
local_address: Vec::new(),
max_speculative: 3,
write_method: WriteMethod::Mmap,
retry_times: 3,
chunk_window: 8 * 1024,
pre_allocate: false,
parse_filename: false,
}
}
}
impl DownloadConfig {
pub fn to_ui_download_config(&self) -> crate::ui::DownloadConfig {
crate::ui::DownloadConfig {
accept_invalid_certs: self.accept_invalid_certs,
accept_invalid_hostnames: self.accept_invalid_hostnames,
headers: self
.headers
.iter()
.map(|(k, v)| format!("{k}: {v}"))
.join("\n")
.into(),
ips: self
.local_address
.iter()
.map(|addr| addr.to_string())
.join("\n")
.into(),
max_speculative: self.max_speculative as i32,
min_chunk_size: self.min_chunk_size as i32,
proxy: match self.proxy.as_deref() {
Proxy::No => "null",
Proxy::System => "",
Proxy::Custom(proxy) => proxy,
}
.into(),
pull_timeout_ms: self.pull_timeout.as_millis() as i32,
retry_gap_ms: self.retry_gap.as_millis() as i32,
save_dir: self.save_dir.to_string_lossy().as_ref().into(),
threads: self.threads as i32,
write_buffer_size: self.write_buffer_size as i32,
write_method: match self.write_method {
WriteMethod::Mmap => 0,
WriteMethod::Std => 1,
},
write_queue_cap: self.write_queue_cap as i32,
retry_times: self.retry_times as i32,
chunk_window: self.chunk_window as i32,
pre_allocate: self.pre_allocate,
file_name: self.file_name.to_shared_string(),
parse_filename: self.parse_filename,
}
}
}
impl From<&crate::ui::DownloadConfig> for DownloadConfig {
fn from(value: &crate::ui::DownloadConfig) -> Self {
Self {
save_dir: value.save_dir.as_str().into(),
file_name: value.file_name.to_string(),
threads: value.threads as usize,
proxy: match value.proxy.as_str() {
"" => Proxy::System,
"null" => Proxy::No,
proxy => Proxy::Custom(proxy.to_string()),
},
headers: parse_header_hashmap(&value.headers),
min_chunk_size: value.min_chunk_size as u64,
write_buffer_size: value.write_buffer_size as usize,
write_queue_cap: value.write_queue_cap as usize,
retry_gap: Duration::from_millis(value.retry_gap_ms as u64),
pull_timeout: Duration::from_millis(value.pull_timeout_ms as u64),
accept_invalid_certs: value.accept_invalid_certs,
accept_invalid_hostnames: value.accept_invalid_hostnames,
local_address: value
.ips
.as_str()
.lines()
.filter_map(|line| line.trim().parse().ok())
.collect(),
max_speculative: value.max_speculative as usize,
write_method: match value.write_method {
1 => WriteMethod::Std,
_ => WriteMethod::Mmap,
},
retry_times: value.retry_times as usize,
chunk_window: value.chunk_window as u64,
pre_allocate: value.pre_allocate,
parse_filename: value.parse_filename,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct GeneralConfig {
pub max_concurrency: usize,
pub auto_start: bool,
pub exit_after_download: bool,
pub ask_before_download: bool,
pub skip_headers: HashSet<String>,
pub run_as_admin: bool,
}
impl Default for GeneralConfig {
fn default() -> Self {
Self {
max_concurrency: 2,
auto_start: false,
exit_after_download: false,
ask_before_download: false,
skip_headers: HashSet::new(),
run_as_admin: false,
}
}
}
impl From<&crate::ui::GeneralConfig> for GeneralConfig {
fn from(value: &crate::ui::GeneralConfig) -> Self {
Self {
max_concurrency: value.max_concurrency as usize,
auto_start: value.auto_start,
exit_after_download: value.exit_after_download,
ask_before_download: value.ask_before_download,
skip_headers: value
.skip_headers
.split('\n')
.map(|s| s.trim().to_lowercase().to_string())
.filter(|s| !s.is_empty())
.collect(),
run_as_admin: value.run_as_admin,
}
}
}
impl GeneralConfig {
pub fn to_ui_general_config(&self) -> crate::ui::GeneralConfig {
crate::ui::GeneralConfig {
max_concurrency: self.max_concurrency as i32,
auto_start: self.auto_start,
exit_after_download: self.exit_after_download,
ask_before_download: self.ask_before_download,
skip_headers: self.skip_headers.iter().join("\n").into(),
run_as_admin: self.run_as_admin,
}
}
}