Skip to main content

rusty_cat/
transfer_task.rs

1use std::path::{Path, PathBuf};
2use std::sync::Arc;
3
4use reqwest::header::HeaderMap;
5use reqwest::Method;
6use tokio::fs::File;
7use tokio::sync::Mutex;
8
9use crate::direction::Direction;
10use crate::http_breakpoint::{BreakpointDownload, BreakpointDownloadHttpConfig, BreakpointUpload};
11use crate::inner::inner_task::InnerTask;
12
13/// Immutable task snapshot exposed to transfer executor implementations.
14///
15/// This type is internally created from [`InnerTask`] and intentionally exposes
16/// read-only accessors.
17#[derive(Clone)]
18pub struct TransferTask {
19    /// Stable file signature.
20    file_sign: String,
21    /// Display file name.
22    file_name: String,
23    /// Local file path.
24    file_path: PathBuf,
25    /// Transfer direction.
26    direction: Direction,
27    /// Total file size in bytes.
28    total_size: u64,
29    /// Chunk size in bytes.
30    chunk_size: u64,
31    /// Request URL.
32    url: String,
33    /// Request HTTP method.
34    method: Method,
35    /// Base request headers.
36    headers: HeaderMap,
37    /// HTTP config for breakpoint download behavior.
38    breakpoint_download_http: BreakpointDownloadHttpConfig,
39    /// Upload breakpoint protocol implementation.
40    breakpoint_upload: Arc<dyn BreakpointUpload + Send + Sync>,
41    /// Download breakpoint protocol implementation.
42    breakpoint_download: Arc<dyn BreakpointDownload + Send + Sync>,
43    /// Optional per-task custom HTTP client.
44    http_client: Option<reqwest::Client>,
45    /// Task-level upload file handle slot to avoid reopening per chunk.
46    upload_file_slot: Arc<Mutex<Option<File>>>,
47    /// Task-level download file handle slot to avoid reopening per chunk.
48    download_file_slot: Arc<Mutex<Option<File>>>,
49}
50
51impl std::fmt::Debug for TransferTask {
52    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53        f.debug_struct("TransferTask")
54            .field("file_sign", &self.file_sign)
55            .field("file_name", &self.file_name)
56            .field("file_path", &self.file_path)
57            .field("direction", &self.direction)
58            .field("total_size", &self.total_size)
59            .field("chunk_size", &self.chunk_size)
60            .field("url", &self.url)
61            .field("method", &self.method)
62            .field("headers", &self.headers)
63            .field("breakpoint_upload", &"<dyn BreakpointUpload>")
64            .field("breakpoint_download", &"<dyn BreakpointDownload>")
65            .field("breakpoint_download_http", &self.breakpoint_download_http)
66            .finish()
67    }
68}
69
70impl TransferTask {
71    /// Creates a transfer snapshot from an internal runtime task.
72    pub(crate) fn from_inner(inner: &InnerTask) -> Self {
73        Self {
74            file_sign: inner.file_sign().to_string(),
75            file_name: inner.file_name().to_string(),
76            file_path: inner.file_path().to_path_buf(),
77            direction: inner.direction(),
78            total_size: inner.total_size(),
79            chunk_size: inner.chunk_size(),
80            url: inner.url().to_string(),
81            method: inner.method(),
82            headers: inner.headers().clone(),
83            breakpoint_download_http: inner.breakpoint_download_http().clone(),
84            breakpoint_upload: inner.breakpoint_upload().clone(),
85            breakpoint_download: inner.breakpoint_download().clone(),
86            http_client: inner.http_client_ref().cloned(),
87            upload_file_slot: Arc::new(Mutex::new(None)),
88            download_file_slot: Arc::new(Mutex::new(None)),
89        }
90    }
91
92    /// Returns transfer direction.
93    ///
94    /// # Examples
95    ///
96    /// ```no_run
97    /// use rusty_cat::api::TransferTask;
98    ///
99    /// fn inspect(task: &TransferTask) {
100    ///     let _ = task.direction();
101    /// }
102    /// ```
103    pub fn direction(&self) -> Direction {
104        self.direction
105    }
106
107    /// Returns total file size in bytes.
108    ///
109    /// # Examples
110    ///
111    /// ```no_run
112    /// use rusty_cat::api::TransferTask;
113    ///
114    /// fn inspect(task: &TransferTask) {
115    ///     let _ = task.total_size();
116    /// }
117    /// ```
118    pub fn total_size(&self) -> u64 {
119        self.total_size
120    }
121
122    /// Returns chunk size in bytes.
123    ///
124    /// # Examples
125    ///
126    /// ```no_run
127    /// use rusty_cat::api::TransferTask;
128    ///
129    /// fn inspect(task: &TransferTask) {
130    ///     let _ = task.chunk_size();
131    /// }
132    /// ```
133    pub fn chunk_size(&self) -> u64 {
134        self.chunk_size
135    }
136
137    /// Returns file signature.
138    ///
139    /// # Examples
140    ///
141    /// ```no_run
142    /// use rusty_cat::api::TransferTask;
143    ///
144    /// fn inspect(task: &TransferTask) {
145    ///     let _ = task.file_sign();
146    /// }
147    /// ```
148    pub fn file_sign(&self) -> &str {
149        &self.file_sign
150    }
151
152    /// Returns display file name.
153    ///
154    /// # Examples
155    ///
156    /// ```no_run
157    /// use rusty_cat::api::TransferTask;
158    ///
159    /// fn inspect(task: &TransferTask) {
160    ///     let _ = task.file_name();
161    /// }
162    /// ```
163    pub fn file_name(&self) -> &str {
164        &self.file_name
165    }
166
167    /// Returns local file path.
168    ///
169    /// # Examples
170    ///
171    /// ```no_run
172    /// use rusty_cat::api::TransferTask;
173    ///
174    /// fn inspect(task: &TransferTask) {
175    ///     let _ = task.file_path();
176    /// }
177    /// ```
178    pub fn file_path(&self) -> &Path {
179        &self.file_path
180    }
181
182    /// Returns request URL.
183    ///
184    /// # Examples
185    ///
186    /// ```no_run
187    /// use rusty_cat::api::TransferTask;
188    ///
189    /// fn inspect(task: &TransferTask) {
190    ///     let _ = task.url();
191    /// }
192    /// ```
193    pub fn url(&self) -> &str {
194        &self.url
195    }
196
197    /// Returns request HTTP method.
198    ///
199    /// # Examples
200    ///
201    /// ```no_run
202    /// use rusty_cat::api::TransferTask;
203    ///
204    /// fn inspect(task: &TransferTask) {
205    ///     let _ = task.method();
206    /// }
207    /// ```
208    pub fn method(&self) -> Method {
209        self.method.clone()
210    }
211
212    /// Returns base request headers.
213    ///
214    /// # Examples
215    ///
216    /// ```no_run
217    /// use rusty_cat::api::TransferTask;
218    ///
219    /// fn inspect(task: &TransferTask) {
220    ///     let _ = task.headers();
221    /// }
222    /// ```
223    pub fn headers(&self) -> &HeaderMap {
224        &self.headers
225    }
226
227    /// Returns task-level breakpoint download HTTP configuration.
228    ///
229    /// Custom [`crate::download_trait::BreakpointDownload`] implementations can
230    /// read values such as `range_accept`.
231    ///
232    /// # Examples
233    ///
234    /// ```no_run
235    /// use rusty_cat::api::TransferTask;
236    ///
237    /// fn inspect(task: &TransferTask) {
238    ///     let _ = task.breakpoint_download_http();
239    /// }
240    /// ```
241    pub fn breakpoint_download_http(&self) -> Option<&BreakpointDownloadHttpConfig> {
242        Some(&self.breakpoint_download_http)
243    }
244
245    /// Returns task-level upload protocol implementation.
246    pub(crate) fn breakpoint_upload(&self) -> Option<&Arc<dyn BreakpointUpload + Send + Sync>> {
247        Some(&self.breakpoint_upload)
248    }
249
250    /// Returns task-level download protocol implementation.
251    pub(crate) fn breakpoint_download(&self) -> Option<&Arc<dyn BreakpointDownload + Send + Sync>> {
252        Some(&self.breakpoint_download)
253    }
254
255    /// Returns task-level custom HTTP client, if configured.
256    pub(crate) fn http_client_ref(&self) -> Option<&reqwest::Client> {
257        self.http_client.as_ref()
258    }
259
260    /// Returns upload file handle slot used by executor.
261    pub(crate) fn upload_file_slot(&self) -> &Arc<Mutex<Option<File>>> {
262        &self.upload_file_slot
263    }
264
265    /// Returns download file handle slot used by executor.
266    pub(crate) fn download_file_slot(&self) -> &Arc<Mutex<Option<File>>> {
267        &self.download_file_slot
268    }
269}