Skip to main content

rusty_cat/
pounce_task.rs

1use std::fmt;
2use std::path::PathBuf;
3use std::sync::Arc;
4
5use reqwest::header::HeaderMap;
6use reqwest::Method;
7
8use crate::direction::Direction;
9use crate::http_breakpoint::{BreakpointDownload, BreakpointDownloadHttpConfig, BreakpointUpload};
10
11/// 仅承载调用方入参,由 [`UploadPounceBuilder`] / [`DownloadPounceBuilder`] 构造
12#[derive(Clone)]
13pub struct PounceTask {
14    pub(crate) direction: Direction,
15    pub(crate) file_name: String,
16    pub(crate) file_path: PathBuf,
17    pub(crate) total_size: u64,
18    pub(crate) chunk_size: u64,
19    pub(crate) url: String,
20    pub(crate) method: Method,
21    pub(crate) headers: HeaderMap,
22    /// 下载任务在进度回调里展示的标识;上传任务忽略,由内部 MD5 填充。
23    pub(crate) client_file_sign: Option<String>,
24    pub(crate) breakpoint_upload: Option<Arc<dyn BreakpointUpload + Send + Sync>>,
25    pub(crate) breakpoint_download: Option<Arc<dyn BreakpointDownload + Send + Sync>>,
26    pub(crate) breakpoint_download_http: Option<BreakpointDownloadHttpConfig>,
27    /// 每个分片的最大重试次数(仅在分片传输失败时生效,不包含 prepare 阶段)。
28    pub(crate) max_chunk_retries: u32,
29}
30
31impl fmt::Debug for PounceTask {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        f.debug_struct("PounceTask")
34            .field("direction", &self.direction)
35            .field("file_name", &self.file_name)
36            .field("file_path", &self.file_path)
37            .field("total_size", &self.total_size)
38            .field("chunk_size", &self.chunk_size)
39            .field("url", &self.url)
40            .field("method", &self.method)
41            .field("headers", &self.headers)
42            .field("client_file_sign", &self.client_file_sign)
43            .field(
44                "breakpoint_upload",
45                &self
46                    .breakpoint_upload
47                    .as_ref()
48                    .map(|_| "Arc<dyn BreakpointUpload + Send + Sync>"),
49            )
50            .field(
51                "breakpoint_download",
52                &self
53                    .breakpoint_download
54                    .as_ref()
55                    .map(|_| "Arc<dyn BreakpointDownload + Send + Sync>"),
56            )
57            .field("breakpoint_download_http", &self.breakpoint_download_http)
58            .field("max_chunk_retries", &self.max_chunk_retries)
59            .finish()
60    }
61}
62
63impl PounceTask {
64    /// 分片重试的默认最大次数:失败后最多再尝试 3 次。
65    pub const DEFAULT_MAX_CHUNK_RETRIES: u32 = 3;
66
67    pub(crate) fn normalized_chunk_size(chunk_size: u64) -> u64 {
68        if chunk_size == 0 {
69            1024 * 1024
70        } else {
71            chunk_size
72        }
73    }
74
75    /// 规范化重试次数:
76    /// - 0 表示“禁用重试”(仅执行一次);
77    /// - 其余值按调用方配置使用。
78    pub(crate) fn normalized_max_chunk_retries(max_chunk_retries: u32) -> u32 {
79        max_chunk_retries
80    }
81
82    pub(crate) fn is_empty(&self) -> bool {
83        self.file_path.as_os_str().is_empty()
84            || self.file_name.is_empty()
85            || self.url.is_empty()
86            || match self.direction {
87                Direction::Upload => self.total_size == 0,
88                Direction::Download => false,
89            }
90    }
91}