Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 132 additions & 64 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ color-eyre = "0.6.5"
crossfire = "3.1.7"
dashmap = { version = "6.1.0", features = ["serde"] }
dirs = "6.0.0"
# fast-down-ffi = { version = "0.2.0", features = ["file", "reqwest-tls", "serde"] }
fast-down-ffi = { path = "../ffi/", features = ["file", "reqwest-tls", "serde"] }
fs4 = { version = "0.13.1", features = ["tokio"] }
fast-down-ffi = { version = "0.2.1", features = ["file", "reqwest-tls", "serde"] }
# fast-down-ffi = { path = "../ffi/", features = ["file", "reqwest-tls", "serde"] }
i-slint-backend-winit = "1.15.1"
image = "0.25.10"
interprocess = { version = "2.4.0", features = ["tokio"] }
Expand All @@ -48,6 +47,7 @@ tracing-appender = "0.2.4"
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
tray-icon = "0.21.3"
url = { version = "2.5.8", features = ["serde"] }
file_alloc = "0.1.2"

[build-dependencies]
slint-build = "1.15.1"
Expand Down
13 changes: 12 additions & 1 deletion src/core/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ use crate::{
utils::{auto_ext, sanitize},
};
use fast_down_ffi::{Event, Total, create_channel, prefetch, unique_path::gen_unique_path};
use file_alloc::FileAlloc;
use parking_lot::Mutex;
use slint::SharedString;
use std::{
ops::Range,
sync::Arc,
time::{Duration, Instant},
};
use tokio::fs;
use tokio::fs::{self, OpenOptions};
use tokio_util::sync::CancellationToken;
use tracing::{error, info, warn};
use url::Url;
Expand Down Expand Up @@ -57,6 +58,7 @@ pub async fn download(
.map(|e| e.progress.clone())
.unwrap_or_default(),
));
let pre_allocate = config.pre_allocate;
let download_config = fast_down_ffi::Config {
retry_times: config.retry_times,
threads: config.threads,
Expand Down Expand Up @@ -115,6 +117,15 @@ pub async fn download(
)
};
on_event(DownloadEvent::Info(Box::new(entry)));
if pre_allocate && total_size > 1024 * 1024 && progress.lock().is_empty() {
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(false)
.open(&save_path)
.await?;
file.allocate(total_size).await?;
}
Ok::<_, color_eyre::Report>((
task,
save_path,
Expand Down
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use fast_down_gui::{
ui::*,
utils::{LogErr, show_task_dialog},
};
use file_alloc::init_fast_alloc;
use rfd::FileDialog;
use slint::{Model, ModelRc, ToSharedString, VecModel};
use std::{collections::HashSet, rc::Rc, sync::Arc};
Expand Down Expand Up @@ -81,6 +82,7 @@ async fn main() -> color_eyre::Result<()> {
let _ = check_ipc_and_wake().await.log_err("检查 ipc 通道错误");
let _ = auto_register().log_err("写入浏览器扩展通信配置失败");
let ui = MainWindow::new()?;
init_fast_alloc();
let db = Database::new().await;
let task_set = TaskSet::new(db.inner.general_config.lock().max_concurrency);
let auto = get_auto_start()
Expand Down
4 changes: 4 additions & 0 deletions src/persist/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct DownloadConfig {
pub write_method: WriteMethod,
pub retry_times: usize,
pub chunk_window: u64,
pub pre_allocate: bool,
}

impl Default for DownloadConfig {
Expand All @@ -43,6 +44,7 @@ impl Default for DownloadConfig {
write_method: WriteMethod::Mmap,
retry_times: 3,
chunk_window: 8 * 1024,
pre_allocate: false,
}
}
}
Expand Down Expand Up @@ -84,6 +86,7 @@ impl DownloadConfig {
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,
}
}
}
Expand Down Expand Up @@ -119,6 +122,7 @@ impl From<&crate::ui::DownloadConfig> for DownloadConfig {
},
retry_times: value.retry_times as usize,
chunk_window: value.chunk_window as u64,
pre_allocate: value.pre_allocate,
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/persist/loader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ mod v1;
mod v2;
mod v3;
mod v4;
mod v5;

use crate::persist::{
DatabaseInner,
loader::{v1::V1Loader, v2::V2Loader, v3::V3Loader, v4::V4Loader},
loader::{v1::V1Loader, v2::V2Loader, v3::V3Loader, v4::V4Loader, v5::V5Loader},
};

pub trait Loader {
Expand All @@ -17,8 +18,9 @@ pub struct BoxLoader;

impl Loader for BoxLoader {
fn load(&self, bytes: &[u8]) -> Option<DatabaseInner> {
V4Loader
V5Loader
.load(bytes)
.or_else(|| V4Loader.load(bytes))
.or_else(|| V3Loader.load(bytes))
.or_else(|| V2Loader.load(bytes))
.or_else(|| V1Loader.load(bytes))
Expand Down
1 change: 1 addition & 0 deletions src/persist/loader/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl From<Config> for crate::persist::DownloadConfig {
local_address: c.local_address,
max_speculative: c.max_speculative,
write_method: c.write_method,
pre_allocate: false,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/persist/loader/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ impl From<Config> for crate::persist::DownloadConfig {
local_address: c.local_address,
max_speculative: c.max_speculative,
write_method: c.write_method,
pre_allocate: false,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/persist/loader/v3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ impl From<DownloadConfig> for crate::persist::DownloadConfig {
local_address: c.local_address,
max_speculative: c.max_speculative,
write_method: c.write_method,
pre_allocate: false,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/persist/loader/v4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ impl From<DownloadConfig> for crate::persist::DownloadConfig {
local_address: c.local_address,
max_speculative: c.max_speculative,
write_method: c.write_method,
pre_allocate: false,
}
}
}
Expand Down
146 changes: 146 additions & 0 deletions src/persist/loader/v5.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use crate::persist::loader::Loader;
use dashmap::DashMap;
use fast_down_ffi::{FileId, ProgressEntry, Proxy, WriteMethod};
use parking_lot::Mutex;
use serde::Deserialize;
use std::{
collections::HashMap, net::IpAddr, path::PathBuf, sync::atomic::AtomicI32, time::Duration,
};
use url::Url;

#[derive(Deserialize, Debug)]
pub struct DownloadConfig {
pub save_dir: PathBuf,
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,
}

#[derive(Deserialize, Debug)]
pub struct GeneralConfig {
pub max_concurrency: usize,
pub auto_start: bool,
pub exit_after_download: bool,
}

impl From<DownloadConfig> for crate::persist::DownloadConfig {
fn from(c: DownloadConfig) -> Self {
Self {
proxy: c.proxy,
retry_times: c.retry_times,
chunk_window: c.chunk_window,
save_dir: c.save_dir,
threads: c.threads,
headers: c.headers,
min_chunk_size: c.min_chunk_size,
write_buffer_size: c.write_buffer_size,
write_queue_cap: c.write_queue_cap,
retry_gap: c.retry_gap,
pull_timeout: c.pull_timeout,
accept_invalid_certs: c.accept_invalid_certs,
accept_invalid_hostnames: c.accept_invalid_hostnames,
local_address: c.local_address,
max_speculative: c.max_speculative,
write_method: c.write_method,
pre_allocate: c.pre_allocate,
}
}
}

impl From<GeneralConfig> for crate::persist::GeneralConfig {
fn from(c: GeneralConfig) -> Self {
Self {
max_concurrency: c.max_concurrency,
auto_start: c.auto_start,
exit_after_download: c.exit_after_download,
}
}
}

#[derive(Deserialize, Debug)]
pub struct DatabaseEntry {
pub file_name: String,
pub file_path: PathBuf,
pub file_size: u64,
pub file_id: FileId,
pub progress: Vec<ProgressEntry>,
pub elapsed: Duration,
pub url: Url,
pub config: DownloadConfig,
pub status: Status,
}

impl From<DatabaseEntry> for crate::persist::DatabaseEntry {
fn from(e: DatabaseEntry) -> Self {
Self {
file_name: e.file_name,
file_path: e.file_path,
file_size: e.file_size,
file_id: e.file_id,
progress: e.progress,
elapsed: e.elapsed,
url: e.url,
config: e.config.into(),
status: e.status.into(),
}
}
}

#[derive(Deserialize, Debug)]
pub enum Status {
Completed,
Error,
Paused,
}

impl From<Status> for crate::persist::Status {
fn from(value: Status) -> Self {
match value {
Status::Completed => crate::persist::Status::Completed,
Status::Error => crate::persist::Status::Error,
Status::Paused => crate::persist::Status::Paused,
}
}
}

#[derive(Deserialize, Debug)]
pub struct DatabaseInner {
pub data: DashMap<i32, DatabaseEntry>,
pub download_config: Mutex<DownloadConfig>,
pub general_config: Mutex<GeneralConfig>,
pub max_gid: AtomicI32,
}

impl From<DatabaseInner> for crate::persist::DatabaseInner {
fn from(db: DatabaseInner) -> Self {
Self {
data: db.data.into_iter().map(|(k, v)| (k, v.into())).collect(),
download_config: Mutex::new(db.download_config.into_inner().into()),
general_config: Mutex::new(db.general_config.into_inner().into()),
max_gid: db.max_gid,
}
}
}

#[derive(Debug, Clone)]
pub struct V5Loader;

impl Loader for V5Loader {
fn load(&self, bytes: &[u8]) -> Option<crate::persist::DatabaseInner> {
let db: DatabaseInner = bitcode::deserialize(bytes).ok()?;
Some(db.into())
}
}
11 changes: 11 additions & 0 deletions ui/settings.slint
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export struct DownloadConfig {
write_method: int,
retry_times: int,
chunk_window: int,
pre_allocate: bool,
}
export struct GeneralConfig {
max_concurrency: int,
Expand Down Expand Up @@ -277,6 +278,16 @@ export component Settings inherits VerticalLayout {
}
}

HorizontalBox {
padding: 0px;

CheckBox {
text: "文件预分配";
horizontal-stretch: 1;
checked <=> download_config.pre-allocate;
}
}

Text {
text: "写入方法";
}
Expand Down