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};
10use crate::upload_source::UploadSource;
11
12/// User-facing task input built by upload/download builders.
13///
14/// This type only carries request parameters. Internal runtime state is created
15/// later when the task is enqueued.
16#[derive(Clone)]
17pub struct PounceTask {
18    /// Transfer direction.
19    pub(crate) direction: Direction,
20    /// Display file name.
21    pub(crate) file_name: String,
22    /// Local source/target path.
23    pub(crate) file_path: PathBuf,
24    /// Upload-only source descriptor.
25    pub(crate) upload_source: Option<UploadSource>,
26    /// Total file size in bytes (upload only at build time).
27    pub(crate) total_size: u64,
28    /// Chunk size in bytes.
29    pub(crate) chunk_size: u64,
30    /// Request URL.
31    pub(crate) url: String,
32    /// Request HTTP method.
33    pub(crate) method: Method,
34    /// Base request headers.
35    pub(crate) headers: HeaderMap,
36    /// Download-only signature shown in callbacks.
37    ///
38    /// Upload tasks ignore this value and use internal signature generation.
39    pub(crate) client_file_sign: Option<String>,
40    /// Optional custom upload breakpoint protocol.
41    pub(crate) breakpoint_upload: Option<Arc<dyn BreakpointUpload + Send + Sync>>,
42    /// Optional custom download breakpoint protocol.
43    pub(crate) breakpoint_download: Option<Arc<dyn BreakpointDownload + Send + Sync>>,
44    /// Optional HTTP configuration for breakpoint download.
45    pub(crate) breakpoint_download_http: Option<BreakpointDownloadHttpConfig>,
46    /// Maximum retry count per chunk transfer.
47    ///
48    /// Applies only to chunk transfer stage, not prepare stage.
49    pub(crate) max_chunk_retries: u32,
50    /// Maximum retry count after the first failed upload `prepare` (`BreakpointUpload::prepare`).
51    ///
52    /// Used only for upload direction; download tasks carry the default but do not consult it.
53    pub(crate) max_upload_prepare_retries: u32,
54}
55
56impl fmt::Debug for PounceTask {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        f.debug_struct("PounceTask")
59            .field("direction", &self.direction)
60            .field("file_name", &self.file_name)
61            .field("file_path", &self.file_path)
62            .field("upload_source", &self.upload_source)
63            .field("total_size", &self.total_size)
64            .field("chunk_size", &self.chunk_size)
65            .field("url", &self.url)
66            .field("method", &self.method)
67            .field("headers", &self.headers)
68            .field("client_file_sign", &self.client_file_sign)
69            .field(
70                "breakpoint_upload",
71                &self
72                    .breakpoint_upload
73                    .as_ref()
74                    .map(|_| "Arc<dyn BreakpointUpload + Send + Sync>"),
75            )
76            .field(
77                "breakpoint_download",
78                &self
79                    .breakpoint_download
80                    .as_ref()
81                    .map(|_| "Arc<dyn BreakpointDownload + Send + Sync>"),
82            )
83            .field("breakpoint_download_http", &self.breakpoint_download_http)
84            .field("max_chunk_retries", &self.max_chunk_retries)
85            .field(
86                "max_upload_prepare_retries",
87                &self.max_upload_prepare_retries,
88            )
89            .finish()
90    }
91}
92
93impl PounceTask {
94    /// Default maximum retry count per chunk transfer.
95    pub const DEFAULT_MAX_CHUNK_RETRIES: u32 = 3;
96
97    /// Default maximum retry count after the first failed upload prepare.
98    pub const DEFAULT_MAX_UPLOAD_PREPARE_RETRIES: u32 = 3;
99
100    /// Normalizes chunk size input.
101    ///
102    /// `0` is converted to `1 MiB`; other values are kept unchanged.
103    pub(crate) fn normalized_chunk_size(chunk_size: u64) -> u64 {
104        if chunk_size == 0 {
105            1024 * 1024
106        } else {
107            chunk_size
108        }
109    }
110
111    /// Normalizes retry count input.
112    ///
113    /// - `0` means "disable retry".
114    /// - Other values are used as-is.
115    pub(crate) fn normalized_max_chunk_retries(max_chunk_retries: u32) -> u32 {
116        max_chunk_retries
117    }
118
119    /// Normalizes upload prepare retry count input (same rules as chunk retries).
120    pub(crate) fn normalized_max_upload_prepare_retries(max_upload_prepare_retries: u32) -> u32 {
121        max_upload_prepare_retries
122    }
123
124    /// Checks whether required task fields are missing/invalid.
125    ///
126    /// For upload, `total_size` must be greater than `0`.
127    pub(crate) fn is_empty(&self) -> bool {
128        self.file_name.is_empty()
129            || self.url.is_empty()
130            || match self.direction {
131                Direction::Upload => self.total_size == 0 || self.upload_source.is_none(),
132                Direction::Download => self.file_path.as_os_str().is_empty(),
133            }
134    }
135}