18e9cee63Sopenharmony_ci// Copyright (C) 2023 Huawei Device Co., Ltd.
28e9cee63Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
38e9cee63Sopenharmony_ci// you may not use this file except in compliance with the License.
48e9cee63Sopenharmony_ci// You may obtain a copy of the License at
58e9cee63Sopenharmony_ci//
68e9cee63Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
78e9cee63Sopenharmony_ci//
88e9cee63Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
98e9cee63Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
108e9cee63Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
118e9cee63Sopenharmony_ci// See the License for the specific language governing permissions and
128e9cee63Sopenharmony_ci// limitations under the License.
138e9cee63Sopenharmony_ci
148e9cee63Sopenharmony_ciuse std::io::{self, SeekFrom};
158e9cee63Sopenharmony_ciuse std::sync::atomic::{AtomicBool, AtomicI64, AtomicU32, AtomicU64, Ordering};
168e9cee63Sopenharmony_ciuse std::sync::{Mutex, MutexGuard};
178e9cee63Sopenharmony_ciuse std::time::Duration;
188e9cee63Sopenharmony_ci
198e9cee63Sopenharmony_ciuse ylong_http_client::async_impl::{Body, Client, Request, RequestBuilder, Response};
208e9cee63Sopenharmony_ciuse ylong_http_client::{ErrorKind, HttpClientError};
218e9cee63Sopenharmony_ciuse ylong_runtime::io::{AsyncSeekExt, AsyncWriteExt};
228e9cee63Sopenharmony_ci
238e9cee63Sopenharmony_cicfg_oh! {
248e9cee63Sopenharmony_ci    use crate::manage::SystemConfig;
258e9cee63Sopenharmony_ci}
268e9cee63Sopenharmony_ci
278e9cee63Sopenharmony_ciuse super::config::{Mode, Version};
288e9cee63Sopenharmony_ciuse super::info::{CommonTaskInfo, State, TaskInfo, UpdateInfo};
298e9cee63Sopenharmony_ciuse super::notify::{EachFileStatus, NotifyData, Progress};
308e9cee63Sopenharmony_ciuse super::reason::Reason;
318e9cee63Sopenharmony_ciuse crate::error::ErrorCode;
328e9cee63Sopenharmony_ciuse crate::manage::database::RequestDb;
338e9cee63Sopenharmony_ciuse crate::manage::network::Network;
348e9cee63Sopenharmony_ciuse crate::manage::notifier::Notifier;
358e9cee63Sopenharmony_ciuse crate::service::client::ClientManagerEntry;
368e9cee63Sopenharmony_ciuse crate::task::client::build_client;
378e9cee63Sopenharmony_ciuse crate::task::config::{Action, TaskConfig};
388e9cee63Sopenharmony_ciuse crate::task::files::{AttachedFiles, Files};
398e9cee63Sopenharmony_ciuse crate::utils::form_item::FileSpec;
408e9cee63Sopenharmony_ciuse crate::utils::get_current_timestamp;
418e9cee63Sopenharmony_ci
428e9cee63Sopenharmony_ciconst RETRY_TIMES: u32 = 4;
438e9cee63Sopenharmony_ciconst RETRY_INTERVAL: u64 = 400;
448e9cee63Sopenharmony_ci
458e9cee63Sopenharmony_cipub(crate) struct RequestTask {
468e9cee63Sopenharmony_ci    pub(crate) conf: TaskConfig,
478e9cee63Sopenharmony_ci    pub(crate) client: Client,
488e9cee63Sopenharmony_ci    pub(crate) files: Files,
498e9cee63Sopenharmony_ci    pub(crate) body_files: Files,
508e9cee63Sopenharmony_ci    pub(crate) ctime: u64,
518e9cee63Sopenharmony_ci    pub(crate) mime_type: Mutex<String>,
528e9cee63Sopenharmony_ci    pub(crate) progress: Mutex<Progress>,
538e9cee63Sopenharmony_ci    pub(crate) status: Mutex<TaskStatus>,
548e9cee63Sopenharmony_ci    pub(crate) code: Mutex<Vec<Reason>>,
558e9cee63Sopenharmony_ci    pub(crate) tries: AtomicU32,
568e9cee63Sopenharmony_ci    pub(crate) background_notify_time: AtomicU64,
578e9cee63Sopenharmony_ci    pub(crate) file_total_size: AtomicI64,
588e9cee63Sopenharmony_ci    pub(crate) rate_limiting: AtomicU64,
598e9cee63Sopenharmony_ci    pub(crate) last_notify: AtomicU64,
608e9cee63Sopenharmony_ci    pub(crate) client_manager: ClientManagerEntry,
618e9cee63Sopenharmony_ci    pub(crate) running_result: Mutex<Option<Result<(), Reason>>>,
628e9cee63Sopenharmony_ci    pub(crate) network: Network,
638e9cee63Sopenharmony_ci    pub(crate) timeout_tries: AtomicU32,
648e9cee63Sopenharmony_ci    pub(crate) upload_resume: AtomicBool,
658e9cee63Sopenharmony_ci}
668e9cee63Sopenharmony_ci
678e9cee63Sopenharmony_ciimpl RequestTask {
688e9cee63Sopenharmony_ci    pub(crate) fn task_id(&self) -> u32 {
698e9cee63Sopenharmony_ci        self.conf.common_data.task_id
708e9cee63Sopenharmony_ci    }
718e9cee63Sopenharmony_ci
728e9cee63Sopenharmony_ci    pub(crate) fn uid(&self) -> u64 {
738e9cee63Sopenharmony_ci        self.conf.common_data.uid
748e9cee63Sopenharmony_ci    }
758e9cee63Sopenharmony_ci
768e9cee63Sopenharmony_ci    pub(crate) fn config(&self) -> &TaskConfig {
778e9cee63Sopenharmony_ci        &self.conf
788e9cee63Sopenharmony_ci    }
798e9cee63Sopenharmony_ci
808e9cee63Sopenharmony_ci    // only use for download task
818e9cee63Sopenharmony_ci    pub(crate) fn mime_type(&self) -> String {
828e9cee63Sopenharmony_ci        self.mime_type.lock().unwrap().clone()
838e9cee63Sopenharmony_ci    }
848e9cee63Sopenharmony_ci
858e9cee63Sopenharmony_ci    pub(crate) fn action(&self) -> Action {
868e9cee63Sopenharmony_ci        self.conf.common_data.action
878e9cee63Sopenharmony_ci    }
888e9cee63Sopenharmony_ci
898e9cee63Sopenharmony_ci    pub(crate) fn mode(&self) -> Mode {
908e9cee63Sopenharmony_ci        self.conf.common_data.mode
918e9cee63Sopenharmony_ci    }
928e9cee63Sopenharmony_ci
938e9cee63Sopenharmony_ci    pub(crate) fn speed_limit(&self, limit: u64) {
948e9cee63Sopenharmony_ci        let old = self.rate_limiting.swap(limit, Ordering::SeqCst);
958e9cee63Sopenharmony_ci        if old != limit {
968e9cee63Sopenharmony_ci            info!("task {} speed_limit {}", self.task_id(), limit);
978e9cee63Sopenharmony_ci        }
988e9cee63Sopenharmony_ci    }
998e9cee63Sopenharmony_ci
1008e9cee63Sopenharmony_ci    pub(crate) async fn network_retry(&self) -> Result<(), TaskError> {
1018e9cee63Sopenharmony_ci        if self.tries.load(Ordering::SeqCst) < RETRY_TIMES {
1028e9cee63Sopenharmony_ci            self.tries.fetch_add(1, Ordering::SeqCst);
1038e9cee63Sopenharmony_ci            if !self.network.is_online() {
1048e9cee63Sopenharmony_ci                return Err(TaskError::Waiting(TaskPhase::NetworkOffline));
1058e9cee63Sopenharmony_ci            } else {
1068e9cee63Sopenharmony_ci                ylong_runtime::time::sleep(Duration::from_millis(RETRY_INTERVAL)).await;
1078e9cee63Sopenharmony_ci                return Err(TaskError::Waiting(TaskPhase::NeedRetry));
1088e9cee63Sopenharmony_ci            }
1098e9cee63Sopenharmony_ci        }
1108e9cee63Sopenharmony_ci        Ok(())
1118e9cee63Sopenharmony_ci    }
1128e9cee63Sopenharmony_ci}
1138e9cee63Sopenharmony_ci
1148e9cee63Sopenharmony_cipub(crate) fn change_upload_size(begins: u64, mut ends: i64, size: i64) -> i64 {
1158e9cee63Sopenharmony_ci    if ends < 0 || ends >= size {
1168e9cee63Sopenharmony_ci        ends = size - 1;
1178e9cee63Sopenharmony_ci    }
1188e9cee63Sopenharmony_ci    if begins as i64 > ends {
1198e9cee63Sopenharmony_ci        return size;
1208e9cee63Sopenharmony_ci    }
1218e9cee63Sopenharmony_ci    ends - begins as i64 + 1
1228e9cee63Sopenharmony_ci}
1238e9cee63Sopenharmony_ci
1248e9cee63Sopenharmony_ciimpl RequestTask {
1258e9cee63Sopenharmony_ci    pub(crate) fn new(
1268e9cee63Sopenharmony_ci        config: TaskConfig,
1278e9cee63Sopenharmony_ci        files: AttachedFiles,
1288e9cee63Sopenharmony_ci        client: Client,
1298e9cee63Sopenharmony_ci        client_manager: ClientManagerEntry,
1308e9cee63Sopenharmony_ci        network: Network,
1318e9cee63Sopenharmony_ci        upload_resume: bool,
1328e9cee63Sopenharmony_ci    ) -> RequestTask {
1338e9cee63Sopenharmony_ci        let file_len = files.files.len();
1348e9cee63Sopenharmony_ci        let action = config.common_data.action;
1358e9cee63Sopenharmony_ci
1368e9cee63Sopenharmony_ci        let file_total_size = match action {
1378e9cee63Sopenharmony_ci            Action::Upload => {
1388e9cee63Sopenharmony_ci                let mut file_total_size = 0i64;
1398e9cee63Sopenharmony_ci                // If the total size overflows, ignore it.
1408e9cee63Sopenharmony_ci                for size in files.sizes.iter() {
1418e9cee63Sopenharmony_ci                    file_total_size += *size;
1428e9cee63Sopenharmony_ci                }
1438e9cee63Sopenharmony_ci                file_total_size
1448e9cee63Sopenharmony_ci            }
1458e9cee63Sopenharmony_ci            Action::Download => -1,
1468e9cee63Sopenharmony_ci            _ => unreachable!("Action::Any in RequestTask::new never reach"),
1478e9cee63Sopenharmony_ci        };
1488e9cee63Sopenharmony_ci
1498e9cee63Sopenharmony_ci        let mut sizes = files.sizes.clone();
1508e9cee63Sopenharmony_ci
1518e9cee63Sopenharmony_ci        if action == Action::Upload && config.common_data.index < sizes.len() as u32 {
1528e9cee63Sopenharmony_ci            sizes[config.common_data.index as usize] = change_upload_size(
1538e9cee63Sopenharmony_ci                config.common_data.begins,
1548e9cee63Sopenharmony_ci                config.common_data.ends,
1558e9cee63Sopenharmony_ci                sizes[config.common_data.index as usize],
1568e9cee63Sopenharmony_ci            );
1578e9cee63Sopenharmony_ci        }
1588e9cee63Sopenharmony_ci
1598e9cee63Sopenharmony_ci        let time = get_current_timestamp();
1608e9cee63Sopenharmony_ci        let status = TaskStatus::new(time);
1618e9cee63Sopenharmony_ci        let progress = Progress::new(sizes);
1628e9cee63Sopenharmony_ci
1638e9cee63Sopenharmony_ci        RequestTask {
1648e9cee63Sopenharmony_ci            conf: config,
1658e9cee63Sopenharmony_ci            client,
1668e9cee63Sopenharmony_ci            files: files.files,
1678e9cee63Sopenharmony_ci            body_files: files.body_files,
1688e9cee63Sopenharmony_ci            ctime: time,
1698e9cee63Sopenharmony_ci            mime_type: Mutex::new(String::new()),
1708e9cee63Sopenharmony_ci            progress: Mutex::new(progress),
1718e9cee63Sopenharmony_ci            tries: AtomicU32::new(0),
1728e9cee63Sopenharmony_ci            status: Mutex::new(status),
1738e9cee63Sopenharmony_ci            code: Mutex::new(vec![Reason::Default; file_len]),
1748e9cee63Sopenharmony_ci            background_notify_time: AtomicU64::new(time),
1758e9cee63Sopenharmony_ci            file_total_size: AtomicI64::new(file_total_size),
1768e9cee63Sopenharmony_ci            rate_limiting: AtomicU64::new(0),
1778e9cee63Sopenharmony_ci            last_notify: AtomicU64::new(time),
1788e9cee63Sopenharmony_ci            client_manager,
1798e9cee63Sopenharmony_ci            running_result: Mutex::new(None),
1808e9cee63Sopenharmony_ci            network,
1818e9cee63Sopenharmony_ci            timeout_tries: AtomicU32::new(0),
1828e9cee63Sopenharmony_ci            upload_resume: AtomicBool::new(upload_resume),
1838e9cee63Sopenharmony_ci        }
1848e9cee63Sopenharmony_ci    }
1858e9cee63Sopenharmony_ci
1868e9cee63Sopenharmony_ci    pub(crate) fn new_by_info(
1878e9cee63Sopenharmony_ci        config: TaskConfig,
1888e9cee63Sopenharmony_ci        #[cfg(feature = "oh")] system: SystemConfig,
1898e9cee63Sopenharmony_ci        info: TaskInfo,
1908e9cee63Sopenharmony_ci        client_manager: ClientManagerEntry,
1918e9cee63Sopenharmony_ci        network: Network,
1928e9cee63Sopenharmony_ci        upload_resume: bool,
1938e9cee63Sopenharmony_ci    ) -> Result<RequestTask, ErrorCode> {
1948e9cee63Sopenharmony_ci        #[cfg(feature = "oh")]
1958e9cee63Sopenharmony_ci        let (files, client) = check_config(&config, system)?;
1968e9cee63Sopenharmony_ci        #[cfg(not(feature = "oh"))]
1978e9cee63Sopenharmony_ci        let (files, client) = check_config(&config)?;
1988e9cee63Sopenharmony_ci
1998e9cee63Sopenharmony_ci        let file_len = files.files.len();
2008e9cee63Sopenharmony_ci        let action = config.common_data.action;
2018e9cee63Sopenharmony_ci        let time = get_current_timestamp();
2028e9cee63Sopenharmony_ci
2038e9cee63Sopenharmony_ci        let file_total_size = match action {
2048e9cee63Sopenharmony_ci            Action::Upload => {
2058e9cee63Sopenharmony_ci                let mut file_total_size = 0i64;
2068e9cee63Sopenharmony_ci                // If the total size overflows, ignore it.
2078e9cee63Sopenharmony_ci                for size in files.sizes.iter() {
2088e9cee63Sopenharmony_ci                    file_total_size += *size;
2098e9cee63Sopenharmony_ci                }
2108e9cee63Sopenharmony_ci                file_total_size
2118e9cee63Sopenharmony_ci            }
2128e9cee63Sopenharmony_ci            Action::Download => *info.progress.sizes.first().unwrap_or(&-1),
2138e9cee63Sopenharmony_ci            _ => unreachable!("Action::Any in RequestTask::new never reach"),
2148e9cee63Sopenharmony_ci        };
2158e9cee63Sopenharmony_ci
2168e9cee63Sopenharmony_ci        // If `TaskInfo` is provided, use data of it.
2178e9cee63Sopenharmony_ci        let ctime = info.common_data.ctime;
2188e9cee63Sopenharmony_ci        let mime_type = info.mime_type.clone();
2198e9cee63Sopenharmony_ci        let tries = info.common_data.tries;
2208e9cee63Sopenharmony_ci        let status = TaskStatus {
2218e9cee63Sopenharmony_ci            mtime: time,
2228e9cee63Sopenharmony_ci            state: State::from(info.progress.common_data.state),
2238e9cee63Sopenharmony_ci            reason: Reason::from(info.common_data.reason),
2248e9cee63Sopenharmony_ci        };
2258e9cee63Sopenharmony_ci        let progress = info.progress;
2268e9cee63Sopenharmony_ci
2278e9cee63Sopenharmony_ci        Ok(RequestTask {
2288e9cee63Sopenharmony_ci            conf: config,
2298e9cee63Sopenharmony_ci            client,
2308e9cee63Sopenharmony_ci            files: files.files,
2318e9cee63Sopenharmony_ci            body_files: files.body_files,
2328e9cee63Sopenharmony_ci            ctime,
2338e9cee63Sopenharmony_ci            mime_type: Mutex::new(mime_type),
2348e9cee63Sopenharmony_ci            progress: Mutex::new(progress),
2358e9cee63Sopenharmony_ci            tries: AtomicU32::new(tries),
2368e9cee63Sopenharmony_ci            status: Mutex::new(status),
2378e9cee63Sopenharmony_ci            code: Mutex::new(vec![Reason::Default; file_len]),
2388e9cee63Sopenharmony_ci            background_notify_time: AtomicU64::new(time),
2398e9cee63Sopenharmony_ci            file_total_size: AtomicI64::new(file_total_size),
2408e9cee63Sopenharmony_ci            rate_limiting: AtomicU64::new(0),
2418e9cee63Sopenharmony_ci            last_notify: AtomicU64::new(time),
2428e9cee63Sopenharmony_ci            client_manager,
2438e9cee63Sopenharmony_ci            running_result: Mutex::new(None),
2448e9cee63Sopenharmony_ci            network,
2458e9cee63Sopenharmony_ci            timeout_tries: AtomicU32::new(0),
2468e9cee63Sopenharmony_ci            upload_resume: AtomicBool::new(upload_resume),
2478e9cee63Sopenharmony_ci        })
2488e9cee63Sopenharmony_ci    }
2498e9cee63Sopenharmony_ci
2508e9cee63Sopenharmony_ci    pub(crate) fn build_notify_data(&self) -> NotifyData {
2518e9cee63Sopenharmony_ci        let vec = self.get_each_file_status();
2528e9cee63Sopenharmony_ci        NotifyData {
2538e9cee63Sopenharmony_ci            bundle: self.conf.bundle.clone(),
2548e9cee63Sopenharmony_ci            // `unwrap` for propagating panics among threads.
2558e9cee63Sopenharmony_ci            progress: self.progress.lock().unwrap().clone(),
2568e9cee63Sopenharmony_ci            action: self.conf.common_data.action,
2578e9cee63Sopenharmony_ci            version: self.conf.version,
2588e9cee63Sopenharmony_ci            each_file_status: vec,
2598e9cee63Sopenharmony_ci            task_id: self.conf.common_data.task_id,
2608e9cee63Sopenharmony_ci        }
2618e9cee63Sopenharmony_ci    }
2628e9cee63Sopenharmony_ci
2638e9cee63Sopenharmony_ci    pub(crate) fn update_progress_in_database(&self) {
2648e9cee63Sopenharmony_ci        let mtime = self.status.lock().unwrap().mtime;
2658e9cee63Sopenharmony_ci        let reason = self.status.lock().unwrap().reason;
2668e9cee63Sopenharmony_ci        let progress = self.progress.lock().unwrap().clone();
2678e9cee63Sopenharmony_ci        let update_info = UpdateInfo {
2688e9cee63Sopenharmony_ci            mtime,
2698e9cee63Sopenharmony_ci            reason: reason.repr,
2708e9cee63Sopenharmony_ci            progress,
2718e9cee63Sopenharmony_ci            each_file_status: RequestTask::get_each_file_status_by_code(
2728e9cee63Sopenharmony_ci                &self.code.lock().unwrap(),
2738e9cee63Sopenharmony_ci                &self.conf.file_specs,
2748e9cee63Sopenharmony_ci            ),
2758e9cee63Sopenharmony_ci            tries: self.tries.load(Ordering::SeqCst),
2768e9cee63Sopenharmony_ci            mime_type: self.mime_type(),
2778e9cee63Sopenharmony_ci        };
2788e9cee63Sopenharmony_ci        RequestDb::get_instance().update_task(self.task_id(), update_info);
2798e9cee63Sopenharmony_ci    }
2808e9cee63Sopenharmony_ci
2818e9cee63Sopenharmony_ci    pub(crate) fn build_request_builder(&self) -> Result<RequestBuilder, HttpClientError> {
2828e9cee63Sopenharmony_ci        use ylong_http_client::async_impl::PercentEncoder;
2838e9cee63Sopenharmony_ci
2848e9cee63Sopenharmony_ci        let url = self.conf.url.clone();
2858e9cee63Sopenharmony_ci        let url = match PercentEncoder::encode(url.as_str()) {
2868e9cee63Sopenharmony_ci            Ok(value) => value,
2878e9cee63Sopenharmony_ci            Err(e) => {
2888e9cee63Sopenharmony_ci                error!("url percent encoding error is {:?}", e);
2898e9cee63Sopenharmony_ci                return Err(e);
2908e9cee63Sopenharmony_ci            }
2918e9cee63Sopenharmony_ci        };
2928e9cee63Sopenharmony_ci
2938e9cee63Sopenharmony_ci        let method = match self.conf.method.to_uppercase().as_str() {
2948e9cee63Sopenharmony_ci            "PUT" => "PUT",
2958e9cee63Sopenharmony_ci            "POST" => "POST",
2968e9cee63Sopenharmony_ci            "GET" => "GET",
2978e9cee63Sopenharmony_ci            _ => match self.conf.common_data.action {
2988e9cee63Sopenharmony_ci                Action::Upload => {
2998e9cee63Sopenharmony_ci                    if self.conf.version == Version::API10 {
3008e9cee63Sopenharmony_ci                        "PUT"
3018e9cee63Sopenharmony_ci                    } else {
3028e9cee63Sopenharmony_ci                        "POST"
3038e9cee63Sopenharmony_ci                    }
3048e9cee63Sopenharmony_ci                }
3058e9cee63Sopenharmony_ci                Action::Download => "GET",
3068e9cee63Sopenharmony_ci                _ => "",
3078e9cee63Sopenharmony_ci            },
3088e9cee63Sopenharmony_ci        };
3098e9cee63Sopenharmony_ci        let mut request = RequestBuilder::new().method(method).url(url.as_str());
3108e9cee63Sopenharmony_ci        for (key, value) in self.conf.headers.iter() {
3118e9cee63Sopenharmony_ci            request = request.header(key.as_str(), value.as_str());
3128e9cee63Sopenharmony_ci        }
3138e9cee63Sopenharmony_ci        Ok(request)
3148e9cee63Sopenharmony_ci    }
3158e9cee63Sopenharmony_ci
3168e9cee63Sopenharmony_ci    pub(crate) async fn clear_downloaded_file(&self) -> Result<(), std::io::Error> {
3178e9cee63Sopenharmony_ci        info!("task {} clear downloaded file", self.task_id());
3188e9cee63Sopenharmony_ci        let file = self.files.get_mut(0).unwrap();
3198e9cee63Sopenharmony_ci        file.set_len(0).await?;
3208e9cee63Sopenharmony_ci        file.seek(SeekFrom::Start(0)).await?;
3218e9cee63Sopenharmony_ci
3228e9cee63Sopenharmony_ci        let mut progress_guard = self.progress.lock().unwrap();
3238e9cee63Sopenharmony_ci        progress_guard.common_data.total_processed = 0;
3248e9cee63Sopenharmony_ci        progress_guard.processed[0] = 0;
3258e9cee63Sopenharmony_ci
3268e9cee63Sopenharmony_ci        Ok(())
3278e9cee63Sopenharmony_ci    }
3288e9cee63Sopenharmony_ci
3298e9cee63Sopenharmony_ci    pub(crate) async fn build_download_request(&self) -> Result<Request, TaskError> {
3308e9cee63Sopenharmony_ci        let mut request_builder = self.build_request_builder()?;
3318e9cee63Sopenharmony_ci
3328e9cee63Sopenharmony_ci        let file = self.files.get_mut(0).unwrap();
3338e9cee63Sopenharmony_ci
3348e9cee63Sopenharmony_ci        let has_downloaded = file.metadata().await?.len();
3358e9cee63Sopenharmony_ci        let resume_download = has_downloaded > 0;
3368e9cee63Sopenharmony_ci        let require_range = self.require_range();
3378e9cee63Sopenharmony_ci
3388e9cee63Sopenharmony_ci        let begins = self.conf.common_data.begins;
3398e9cee63Sopenharmony_ci        let ends = self.conf.common_data.ends;
3408e9cee63Sopenharmony_ci
3418e9cee63Sopenharmony_ci        debug!(
3428e9cee63Sopenharmony_ci            "task {} build download request, resume_download: {}, require_range: {}",
3438e9cee63Sopenharmony_ci            self.task_id(),
3448e9cee63Sopenharmony_ci            resume_download,
3458e9cee63Sopenharmony_ci            require_range
3468e9cee63Sopenharmony_ci        );
3478e9cee63Sopenharmony_ci        match (resume_download, require_range) {
3488e9cee63Sopenharmony_ci            (true, false) => {
3498e9cee63Sopenharmony_ci                let (builder, support_range) = self.support_range(request_builder);
3508e9cee63Sopenharmony_ci                request_builder = builder;
3518e9cee63Sopenharmony_ci                if support_range {
3528e9cee63Sopenharmony_ci                    request_builder =
3538e9cee63Sopenharmony_ci                        self.range_request(request_builder, begins + has_downloaded, ends);
3548e9cee63Sopenharmony_ci                } else {
3558e9cee63Sopenharmony_ci                    self.clear_downloaded_file().await?;
3568e9cee63Sopenharmony_ci                }
3578e9cee63Sopenharmony_ci            }
3588e9cee63Sopenharmony_ci            (false, true) => {
3598e9cee63Sopenharmony_ci                request_builder = self.range_request(request_builder, begins, ends);
3608e9cee63Sopenharmony_ci            }
3618e9cee63Sopenharmony_ci            (true, true) => {
3628e9cee63Sopenharmony_ci                let (builder, support_range) = self.support_range(request_builder);
3638e9cee63Sopenharmony_ci                request_builder = builder;
3648e9cee63Sopenharmony_ci                if support_range {
3658e9cee63Sopenharmony_ci                    request_builder =
3668e9cee63Sopenharmony_ci                        self.range_request(request_builder, begins + has_downloaded, ends);
3678e9cee63Sopenharmony_ci                } else {
3688e9cee63Sopenharmony_ci                    return Err(TaskError::Failed(Reason::UnsupportedRangeRequest));
3698e9cee63Sopenharmony_ci                }
3708e9cee63Sopenharmony_ci            }
3718e9cee63Sopenharmony_ci            (false, false) => {}
3728e9cee63Sopenharmony_ci        };
3738e9cee63Sopenharmony_ci
3748e9cee63Sopenharmony_ci        let request = request_builder.body(Body::slice(self.conf.data.clone()))?;
3758e9cee63Sopenharmony_ci        Ok(request)
3768e9cee63Sopenharmony_ci    }
3778e9cee63Sopenharmony_ci
3788e9cee63Sopenharmony_ci    fn range_request(
3798e9cee63Sopenharmony_ci        &self,
3808e9cee63Sopenharmony_ci        request_builder: RequestBuilder,
3818e9cee63Sopenharmony_ci        begins: u64,
3828e9cee63Sopenharmony_ci        ends: i64,
3838e9cee63Sopenharmony_ci    ) -> RequestBuilder {
3848e9cee63Sopenharmony_ci        let range = if ends < 0 {
3858e9cee63Sopenharmony_ci            format!("bytes={begins}-")
3868e9cee63Sopenharmony_ci        } else {
3878e9cee63Sopenharmony_ci            format!("bytes={begins}-{ends}")
3888e9cee63Sopenharmony_ci        };
3898e9cee63Sopenharmony_ci        request_builder.header("Range", range.as_str())
3908e9cee63Sopenharmony_ci    }
3918e9cee63Sopenharmony_ci
3928e9cee63Sopenharmony_ci    fn support_range(&self, mut request_builder: RequestBuilder) -> (RequestBuilder, bool) {
3938e9cee63Sopenharmony_ci        let progress_guard = self.progress.lock().unwrap();
3948e9cee63Sopenharmony_ci        let mut support_range = false;
3958e9cee63Sopenharmony_ci        if let Some(etag) = progress_guard.extras.get("etag") {
3968e9cee63Sopenharmony_ci            request_builder = request_builder.header("If-Range", etag.as_str());
3978e9cee63Sopenharmony_ci            support_range = true;
3988e9cee63Sopenharmony_ci        } else if let Some(last_modified) = progress_guard.extras.get("last-modified") {
3998e9cee63Sopenharmony_ci            request_builder = request_builder.header("If-Range", last_modified.as_str());
4008e9cee63Sopenharmony_ci            support_range = true;
4018e9cee63Sopenharmony_ci        }
4028e9cee63Sopenharmony_ci        if !support_range {
4038e9cee63Sopenharmony_ci            info!("task {} not support range", self.task_id());
4048e9cee63Sopenharmony_ci        }
4058e9cee63Sopenharmony_ci        (request_builder, support_range)
4068e9cee63Sopenharmony_ci    }
4078e9cee63Sopenharmony_ci
4088e9cee63Sopenharmony_ci    pub(crate) fn get_file_info(&self, response: &Response) -> Result<(), TaskError> {
4098e9cee63Sopenharmony_ci        let content_type = response.headers().get("content-type");
4108e9cee63Sopenharmony_ci        if let Some(mime_type) = content_type {
4118e9cee63Sopenharmony_ci            if let Ok(value) = mime_type.to_string() {
4128e9cee63Sopenharmony_ci                *self.mime_type.lock().unwrap() = value;
4138e9cee63Sopenharmony_ci            }
4148e9cee63Sopenharmony_ci        }
4158e9cee63Sopenharmony_ci
4168e9cee63Sopenharmony_ci        let content_length = response.headers().get("content-length");
4178e9cee63Sopenharmony_ci        if let Some(Ok(len)) = content_length.map(|v| v.to_string()) {
4188e9cee63Sopenharmony_ci            match len.parse::<i64>() {
4198e9cee63Sopenharmony_ci                Ok(v) => {
4208e9cee63Sopenharmony_ci                    let mut progress = self.progress.lock().unwrap();
4218e9cee63Sopenharmony_ci                    progress.sizes = vec![v + progress.processed[0] as i64];
4228e9cee63Sopenharmony_ci                    self.file_total_size.store(v, Ordering::SeqCst);
4238e9cee63Sopenharmony_ci                    debug!("the download task content-length is {}", v);
4248e9cee63Sopenharmony_ci                }
4258e9cee63Sopenharmony_ci                Err(e) => {
4268e9cee63Sopenharmony_ci                    error!("convert string to i64 error: {:?}", e);
4278e9cee63Sopenharmony_ci                }
4288e9cee63Sopenharmony_ci            }
4298e9cee63Sopenharmony_ci        } else {
4308e9cee63Sopenharmony_ci            error!("cannot get content-length of the task");
4318e9cee63Sopenharmony_ci            if self.conf.common_data.precise {
4328e9cee63Sopenharmony_ci                return Err(TaskError::Failed(Reason::GetFileSizeFailed));
4338e9cee63Sopenharmony_ci            }
4348e9cee63Sopenharmony_ci        }
4358e9cee63Sopenharmony_ci        Ok(())
4368e9cee63Sopenharmony_ci    }
4378e9cee63Sopenharmony_ci
4388e9cee63Sopenharmony_ci    pub(crate) async fn handle_download_error(
4398e9cee63Sopenharmony_ci        &self,
4408e9cee63Sopenharmony_ci        err: HttpClientError,
4418e9cee63Sopenharmony_ci    ) -> Result<(), TaskError> {
4428e9cee63Sopenharmony_ci        if err.error_kind() != ErrorKind::UserAborted {
4438e9cee63Sopenharmony_ci            error!("Task {} {:?}", self.task_id(), err);
4448e9cee63Sopenharmony_ci        }
4458e9cee63Sopenharmony_ci        match err.error_kind() {
4468e9cee63Sopenharmony_ci            ErrorKind::Timeout => Err(TaskError::Failed(Reason::ContinuousTaskTimeout)),
4478e9cee63Sopenharmony_ci            // user triggered
4488e9cee63Sopenharmony_ci            ErrorKind::UserAborted => Err(TaskError::Waiting(TaskPhase::UserAbort)),
4498e9cee63Sopenharmony_ci            ErrorKind::BodyTransfer | ErrorKind::BodyDecode => {
4508e9cee63Sopenharmony_ci                self.network_retry().await?;
4518e9cee63Sopenharmony_ci                Err(TaskError::Failed(Reason::OthersError))
4528e9cee63Sopenharmony_ci            }
4538e9cee63Sopenharmony_ci            _ => {
4548e9cee63Sopenharmony_ci                if format!("{}", err).contains("No space left on device") {
4558e9cee63Sopenharmony_ci                    Err(TaskError::Failed(Reason::InsufficientSpace))
4568e9cee63Sopenharmony_ci                } else {
4578e9cee63Sopenharmony_ci                    Err(TaskError::Failed(Reason::OthersError))
4588e9cee63Sopenharmony_ci                }
4598e9cee63Sopenharmony_ci            }
4608e9cee63Sopenharmony_ci        }
4618e9cee63Sopenharmony_ci    }
4628e9cee63Sopenharmony_ci
4638e9cee63Sopenharmony_ci    #[cfg(feature = "oh")]
4648e9cee63Sopenharmony_ci    pub(crate) fn notify_response(&self, response: &Response) {
4658e9cee63Sopenharmony_ci        let tid = self.conf.common_data.task_id;
4668e9cee63Sopenharmony_ci        let version: String = response.version().as_str().into();
4678e9cee63Sopenharmony_ci        let status_code: u32 = response.status().as_u16() as u32;
4688e9cee63Sopenharmony_ci        let status_message: String;
4698e9cee63Sopenharmony_ci        if let Some(reason) = response.status().reason() {
4708e9cee63Sopenharmony_ci            status_message = reason.into();
4718e9cee63Sopenharmony_ci        } else {
4728e9cee63Sopenharmony_ci            error!("bad status_message {:?}", status_code);
4738e9cee63Sopenharmony_ci            return;
4748e9cee63Sopenharmony_ci        }
4758e9cee63Sopenharmony_ci        let headers = response.headers().clone();
4768e9cee63Sopenharmony_ci        debug!("notify_response");
4778e9cee63Sopenharmony_ci        self.client_manager
4788e9cee63Sopenharmony_ci            .send_response(tid, version, status_code, status_message, headers)
4798e9cee63Sopenharmony_ci    }
4808e9cee63Sopenharmony_ci
4818e9cee63Sopenharmony_ci    pub(crate) fn require_range(&self) -> bool {
4828e9cee63Sopenharmony_ci        self.conf.common_data.begins > 0 || self.conf.common_data.ends >= 0
4838e9cee63Sopenharmony_ci    }
4848e9cee63Sopenharmony_ci
4858e9cee63Sopenharmony_ci    pub(crate) async fn record_upload_response(
4868e9cee63Sopenharmony_ci        &self,
4878e9cee63Sopenharmony_ci        index: usize,
4888e9cee63Sopenharmony_ci        response: Result<Response, HttpClientError>,
4898e9cee63Sopenharmony_ci    ) {
4908e9cee63Sopenharmony_ci        if let Ok(mut r) = response {
4918e9cee63Sopenharmony_ci            {
4928e9cee63Sopenharmony_ci                let mut guard = self.progress.lock().unwrap();
4938e9cee63Sopenharmony_ci                guard.extras.clear();
4948e9cee63Sopenharmony_ci                for (k, v) in r.headers() {
4958e9cee63Sopenharmony_ci                    if let Ok(value) = v.to_string() {
4968e9cee63Sopenharmony_ci                        guard.extras.insert(k.to_string().to_lowercase(), value);
4978e9cee63Sopenharmony_ci                    }
4988e9cee63Sopenharmony_ci                }
4998e9cee63Sopenharmony_ci            }
5008e9cee63Sopenharmony_ci
5018e9cee63Sopenharmony_ci            let file = match self.body_files.get_mut(index) {
5028e9cee63Sopenharmony_ci                Some(file) => file,
5038e9cee63Sopenharmony_ci                None => return,
5048e9cee63Sopenharmony_ci            };
5058e9cee63Sopenharmony_ci            let _ = file.set_len(0).await;
5068e9cee63Sopenharmony_ci            loop {
5078e9cee63Sopenharmony_ci                let mut buf = [0u8; 1024];
5088e9cee63Sopenharmony_ci                let size = r.data(&mut buf).await;
5098e9cee63Sopenharmony_ci                let size = match size {
5108e9cee63Sopenharmony_ci                    Ok(size) => size,
5118e9cee63Sopenharmony_ci                    Err(_e) => break,
5128e9cee63Sopenharmony_ci                };
5138e9cee63Sopenharmony_ci
5148e9cee63Sopenharmony_ci                if size == 0 {
5158e9cee63Sopenharmony_ci                    break;
5168e9cee63Sopenharmony_ci                }
5178e9cee63Sopenharmony_ci                let _ = file.write_all(&buf[..size]).await;
5188e9cee63Sopenharmony_ci            }
5198e9cee63Sopenharmony_ci            // Makes sure all the data has been written to the target file.
5208e9cee63Sopenharmony_ci            let _ = file.sync_all().await;
5218e9cee63Sopenharmony_ci        }
5228e9cee63Sopenharmony_ci    }
5238e9cee63Sopenharmony_ci
5248e9cee63Sopenharmony_ci    pub(crate) fn get_each_file_status(&self) -> Vec<EachFileStatus> {
5258e9cee63Sopenharmony_ci        let mut vec = Vec::new();
5268e9cee63Sopenharmony_ci        // `unwrap` for propagating panics among threads.
5278e9cee63Sopenharmony_ci        let codes_guard = self.code.lock().unwrap();
5288e9cee63Sopenharmony_ci        for (i, file_spec) in self.conf.file_specs.iter().enumerate() {
5298e9cee63Sopenharmony_ci            let reason = *codes_guard.get(i).unwrap_or(&Reason::Default);
5308e9cee63Sopenharmony_ci            vec.push(EachFileStatus {
5318e9cee63Sopenharmony_ci                path: file_spec.path.clone(),
5328e9cee63Sopenharmony_ci                reason,
5338e9cee63Sopenharmony_ci                message: reason.to_str().into(),
5348e9cee63Sopenharmony_ci            });
5358e9cee63Sopenharmony_ci        }
5368e9cee63Sopenharmony_ci        vec
5378e9cee63Sopenharmony_ci    }
5388e9cee63Sopenharmony_ci
5398e9cee63Sopenharmony_ci    pub(crate) fn get_each_file_status_by_code(
5408e9cee63Sopenharmony_ci        codes_guard: &MutexGuard<Vec<Reason>>,
5418e9cee63Sopenharmony_ci        file_specs: &[FileSpec],
5428e9cee63Sopenharmony_ci    ) -> Vec<EachFileStatus> {
5438e9cee63Sopenharmony_ci        let mut vec = Vec::new();
5448e9cee63Sopenharmony_ci        for (i, file_spec) in file_specs.iter().enumerate() {
5458e9cee63Sopenharmony_ci            let reason = *codes_guard.get(i).unwrap_or(&Reason::Default);
5468e9cee63Sopenharmony_ci            vec.push(EachFileStatus {
5478e9cee63Sopenharmony_ci                path: file_spec.path.clone(),
5488e9cee63Sopenharmony_ci                reason,
5498e9cee63Sopenharmony_ci                message: reason.to_str().into(),
5508e9cee63Sopenharmony_ci            });
5518e9cee63Sopenharmony_ci        }
5528e9cee63Sopenharmony_ci        vec
5538e9cee63Sopenharmony_ci    }
5548e9cee63Sopenharmony_ci
5558e9cee63Sopenharmony_ci    pub(crate) fn info(&self) -> TaskInfo {
5568e9cee63Sopenharmony_ci        let status = self.status.lock().unwrap();
5578e9cee63Sopenharmony_ci        let progress = self.progress.lock().unwrap();
5588e9cee63Sopenharmony_ci        TaskInfo {
5598e9cee63Sopenharmony_ci            bundle: self.conf.bundle.clone(),
5608e9cee63Sopenharmony_ci            url: self.conf.url.clone(),
5618e9cee63Sopenharmony_ci            data: self.conf.data.clone(),
5628e9cee63Sopenharmony_ci            token: self.conf.token.clone(),
5638e9cee63Sopenharmony_ci            form_items: self.conf.form_items.clone(),
5648e9cee63Sopenharmony_ci            file_specs: self.conf.file_specs.clone(),
5658e9cee63Sopenharmony_ci            title: self.conf.title.clone(),
5668e9cee63Sopenharmony_ci            description: self.conf.description.clone(),
5678e9cee63Sopenharmony_ci            mime_type: {
5688e9cee63Sopenharmony_ci                match self.conf.version {
5698e9cee63Sopenharmony_ci                    Version::API10 => match self.conf.common_data.action {
5708e9cee63Sopenharmony_ci                        Action::Download => match self.conf.headers.get("Content-Type") {
5718e9cee63Sopenharmony_ci                            None => "".into(),
5728e9cee63Sopenharmony_ci                            Some(v) => v.clone(),
5738e9cee63Sopenharmony_ci                        },
5748e9cee63Sopenharmony_ci                        Action::Upload => "multipart/form-data".into(),
5758e9cee63Sopenharmony_ci                        _ => "".into(),
5768e9cee63Sopenharmony_ci                    },
5778e9cee63Sopenharmony_ci                    Version::API9 => self.mime_type.lock().unwrap().clone(),
5788e9cee63Sopenharmony_ci                }
5798e9cee63Sopenharmony_ci            },
5808e9cee63Sopenharmony_ci            progress: progress.clone(),
5818e9cee63Sopenharmony_ci            extras: progress.extras.clone(),
5828e9cee63Sopenharmony_ci            each_file_status: self.get_each_file_status(),
5838e9cee63Sopenharmony_ci            common_data: CommonTaskInfo {
5848e9cee63Sopenharmony_ci                task_id: self.conf.common_data.task_id,
5858e9cee63Sopenharmony_ci                uid: self.conf.common_data.uid,
5868e9cee63Sopenharmony_ci                action: self.conf.common_data.action.repr,
5878e9cee63Sopenharmony_ci                mode: self.conf.common_data.mode.repr,
5888e9cee63Sopenharmony_ci                ctime: self.ctime,
5898e9cee63Sopenharmony_ci                mtime: status.mtime,
5908e9cee63Sopenharmony_ci                reason: status.reason.repr,
5918e9cee63Sopenharmony_ci                gauge: self.conf.common_data.gauge,
5928e9cee63Sopenharmony_ci                retry: self.conf.common_data.retry,
5938e9cee63Sopenharmony_ci                tries: self.tries.load(Ordering::SeqCst),
5948e9cee63Sopenharmony_ci                version: self.conf.version as u8,
5958e9cee63Sopenharmony_ci                priority: self.conf.common_data.priority,
5968e9cee63Sopenharmony_ci            },
5978e9cee63Sopenharmony_ci        }
5988e9cee63Sopenharmony_ci    }
5998e9cee63Sopenharmony_ci
6008e9cee63Sopenharmony_ci    pub(crate) fn notify_header_receive(&self) {
6018e9cee63Sopenharmony_ci        if self.conf.version == Version::API9 && self.conf.common_data.action == Action::Upload {
6028e9cee63Sopenharmony_ci            let notify_data = self.build_notify_data();
6038e9cee63Sopenharmony_ci
6048e9cee63Sopenharmony_ci            Notifier::header_receive(&self.client_manager, notify_data);
6058e9cee63Sopenharmony_ci        }
6068e9cee63Sopenharmony_ci    }
6078e9cee63Sopenharmony_ci}
6088e9cee63Sopenharmony_ci
6098e9cee63Sopenharmony_ci#[derive(Clone, Debug)]
6108e9cee63Sopenharmony_cipub(crate) struct TaskStatus {
6118e9cee63Sopenharmony_ci    pub(crate) mtime: u64,
6128e9cee63Sopenharmony_ci    pub(crate) state: State,
6138e9cee63Sopenharmony_ci    pub(crate) reason: Reason,
6148e9cee63Sopenharmony_ci}
6158e9cee63Sopenharmony_ci
6168e9cee63Sopenharmony_ciimpl TaskStatus {
6178e9cee63Sopenharmony_ci    pub(crate) fn new(mtime: u64) -> Self {
6188e9cee63Sopenharmony_ci        TaskStatus {
6198e9cee63Sopenharmony_ci            mtime,
6208e9cee63Sopenharmony_ci            state: State::Initialized,
6218e9cee63Sopenharmony_ci            reason: Reason::Default,
6228e9cee63Sopenharmony_ci        }
6238e9cee63Sopenharmony_ci    }
6248e9cee63Sopenharmony_ci}
6258e9cee63Sopenharmony_ci
6268e9cee63Sopenharmony_cifn check_file_specs(file_specs: &[FileSpec]) -> bool {
6278e9cee63Sopenharmony_ci    const EL1: &str = "/data/storage/el1/base/";
6288e9cee63Sopenharmony_ci    const EL2: &str = "/data/storage/el2/base/";
6298e9cee63Sopenharmony_ci    const EL5: &str = "/data/storage/el5/base/";
6308e9cee63Sopenharmony_ci
6318e9cee63Sopenharmony_ci    let mut result = true;
6328e9cee63Sopenharmony_ci    for (idx, spec) in file_specs.iter().enumerate() {
6338e9cee63Sopenharmony_ci        let path = &spec.path;
6348e9cee63Sopenharmony_ci        if !spec.is_user_file
6358e9cee63Sopenharmony_ci            && !path.starts_with(EL1)
6368e9cee63Sopenharmony_ci            && !path.starts_with(EL2)
6378e9cee63Sopenharmony_ci            && !path.starts_with(EL5)
6388e9cee63Sopenharmony_ci        {
6398e9cee63Sopenharmony_ci            error!("File path invalid - path: {}, idx: {}", path, idx);
6408e9cee63Sopenharmony_ci            result = false;
6418e9cee63Sopenharmony_ci            break;
6428e9cee63Sopenharmony_ci        }
6438e9cee63Sopenharmony_ci    }
6448e9cee63Sopenharmony_ci
6458e9cee63Sopenharmony_ci    result
6468e9cee63Sopenharmony_ci}
6478e9cee63Sopenharmony_ci
6488e9cee63Sopenharmony_cipub(crate) fn check_config(
6498e9cee63Sopenharmony_ci    config: &TaskConfig,
6508e9cee63Sopenharmony_ci    #[cfg(feature = "oh")] system: SystemConfig,
6518e9cee63Sopenharmony_ci) -> Result<(AttachedFiles, Client), ErrorCode> {
6528e9cee63Sopenharmony_ci    if !check_file_specs(&config.file_specs) {
6538e9cee63Sopenharmony_ci        return Err(ErrorCode::Other);
6548e9cee63Sopenharmony_ci    }
6558e9cee63Sopenharmony_ci    let files = AttachedFiles::open(config).map_err(|_| ErrorCode::FileOperationErr)?;
6568e9cee63Sopenharmony_ci    #[cfg(feature = "oh")]
6578e9cee63Sopenharmony_ci    let client = build_client(config, system).map_err(|_| ErrorCode::Other)?;
6588e9cee63Sopenharmony_ci
6598e9cee63Sopenharmony_ci    #[cfg(not(feature = "oh"))]
6608e9cee63Sopenharmony_ci    let client = build_client(config).map_err(|_| ErrorCode::Other)?;
6618e9cee63Sopenharmony_ci    Ok((files, client))
6628e9cee63Sopenharmony_ci}
6638e9cee63Sopenharmony_ci
6648e9cee63Sopenharmony_ciimpl From<HttpClientError> for TaskError {
6658e9cee63Sopenharmony_ci    fn from(_value: HttpClientError) -> Self {
6668e9cee63Sopenharmony_ci        TaskError::Failed(Reason::BuildRequestFailed)
6678e9cee63Sopenharmony_ci    }
6688e9cee63Sopenharmony_ci}
6698e9cee63Sopenharmony_ci
6708e9cee63Sopenharmony_ciimpl From<io::Error> for TaskError {
6718e9cee63Sopenharmony_ci    fn from(_value: io::Error) -> Self {
6728e9cee63Sopenharmony_ci        TaskError::Failed(Reason::IoError)
6738e9cee63Sopenharmony_ci    }
6748e9cee63Sopenharmony_ci}
6758e9cee63Sopenharmony_ci
6768e9cee63Sopenharmony_ci#[derive(Debug, PartialEq, Eq)]
6778e9cee63Sopenharmony_cipub enum TaskPhase {
6788e9cee63Sopenharmony_ci    NeedRetry,
6798e9cee63Sopenharmony_ci    UserAbort,
6808e9cee63Sopenharmony_ci    NetworkOffline,
6818e9cee63Sopenharmony_ci}
6828e9cee63Sopenharmony_ci
6838e9cee63Sopenharmony_ci#[derive(Debug, PartialEq, Eq)]
6848e9cee63Sopenharmony_cipub enum TaskError {
6858e9cee63Sopenharmony_ci    Failed(Reason),
6868e9cee63Sopenharmony_ci    Waiting(TaskPhase),
6878e9cee63Sopenharmony_ci}
6888e9cee63Sopenharmony_ci
6898e9cee63Sopenharmony_ci#[cfg(test)]
6908e9cee63Sopenharmony_cimod test {
6918e9cee63Sopenharmony_ci    use crate::task::request_task::change_upload_size;
6928e9cee63Sopenharmony_ci
6938e9cee63Sopenharmony_ci    #[test]
6948e9cee63Sopenharmony_ci    fn ut_upload_size() {
6958e9cee63Sopenharmony_ci        assert_eq!(change_upload_size(0, -1, 30), 30);
6968e9cee63Sopenharmony_ci        assert_eq!(change_upload_size(10, -1, 30), 20);
6978e9cee63Sopenharmony_ci        assert_eq!(change_upload_size(0, 10, 30), 11);
6988e9cee63Sopenharmony_ci        assert_eq!(change_upload_size(10, 10, 100), 1);
6998e9cee63Sopenharmony_ci        assert_eq!(change_upload_size(0, 30, 30), 30);
7008e9cee63Sopenharmony_ci        assert_eq!(change_upload_size(0, 0, 0), 0);
7018e9cee63Sopenharmony_ci        assert_eq!(change_upload_size(10, 9, 100), 100);
7028e9cee63Sopenharmony_ci    }
7038e9cee63Sopenharmony_ci}
704