fast-down-gui 0.1.45

超级快的下载器图形化界面
Documentation
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,
        }
    }
}