// Copyright (C) 2025 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Task management operations for the RequestProxy.
//!
//! This module implements methods for managing download tasks through the
//! RequestProxy, including creating, starting, pausing, resuming, removing,
//! stopping, and setting speed limits for tasks.
// IPC and parcel dependencies
use ipc::parcel::MsgParcel;
// Download core dependencies
use request_core::config::TaskConfig;
use request_core::interface;
// Local dependencies
use super::{RequestProxy, SERVICE_TOKEN};
use crate::client::error::CreateTaskError;
impl RequestProxy {
/// Creates a new download task with the provided configuration.
///
/// Sends a request to the download service to create a new task based on
/// the provided `TaskConfig`. Returns the unique task ID if successful.
///
/// # Arguments
/// * `config` - The task configuration containing download parameters
///
/// # Returns
/// - `Ok(i64)` with the task ID if the task was created successfully
/// - `Err(CreateTaskError)` if an error occurred during task creation
///
/// # Examples
///
/// ```rust,no_run
/// use request_core::config::TaskConfig;
/// use request_next::proxy::RequestProxy;
///
/// fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let proxy = RequestProxy::get_instance();
/// let config = TaskConfig::default();
///
/// match proxy.create(&config) {
/// Ok(task_id) => println!("Task created with ID: {}", task_id),
/// Err(e) => eprintln!("Failed to create task: {:?}", e),
/// }
///
/// Ok(())
/// }
/// ```
///
/// # Panics
/// - Panics if parcel operations fail due to IPC errors
pub(crate) fn create(&self, config: &TaskConfig) -> Result<i64, CreateTaskError> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
// Write interface token to identify the service
data.write_interface_token(SERVICE_TOKEN).unwrap();
// Write version information and task configuration
data.write(&1u32).unwrap();
data.write(config).unwrap();
// Send request to construct the task
let mut reply = remote
.send_request(interface::CONSTRUCT, &mut data)
.map_err(|_| 13400003)?;
// Check first error code
let code = reply.read::<i32>().unwrap();
if code != 0 {
return Err(CreateTaskError::Code(code));
}
// Check second error code
let code = reply.read::<i32>().unwrap();
if code != 0 {
return Err(CreateTaskError::Code(code));
}
// Read and return the task ID
let task_id = reply.read::<u32>().unwrap();
Ok(task_id as i64)
}
/// Starts a download task identified by the given task ID.
///
/// # Arguments
/// * `task_id` - The unique identifier of the task to start
///
/// # Returns
/// - `Ok(())` if the task started successfully
/// - `Err(i32)` with the error code if starting the task failed
///
/// # Examples
///
/// ```rust,no_run
/// use request_next::proxy::RequestProxy;
///
/// fn example(task_id: i64) {
/// let proxy = RequestProxy::get_instance();
///
/// match proxy.start(task_id) {
/// Ok(_) => println!("Task {} started successfully", task_id),
/// Err(code) => eprintln!("Failed to start task {} with error code: {}", task_id, code),
/// }
/// }
/// ```
///
/// # Panics
/// - Panics if parcel operations fail due to IPC errors
pub(crate) fn start(&self, task_id: i64) -> Result<(), i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
// Write task count and ID
data.write(&1u32).unwrap();
data.write(&task_id.to_string()).unwrap();
// Send start request
let mut reply = remote
.send_request(interface::START, &mut data)
.map_err(|_| 13400003)?;
let code = reply.read::<i32>().unwrap(); // error code
if code == 0 {
let code = reply.read::<i32>().unwrap(); // error code
if code == 0 {
Ok(())
} else {
Err(code)
}
} else {
Err(code)
}
}
/// Pauses a running download task.
///
/// # Arguments
/// * `task_id` - The unique identifier of the task to pause
///
/// # Returns
/// - `Ok(())` if the task was paused successfully
/// - `Err(i32)` with the error code if pausing the task failed
///
/// # Examples
///
/// ```rust,no_run
/// use request_next::proxy::RequestProxy;
///
/// fn example(task_id: i64) {
/// let proxy = RequestProxy::get_instance();
///
/// match proxy.pause(task_id) {
/// Ok(_) => println!("Task {} paused successfully", task_id),
/// Err(code) => eprintln!("Failed to pause task {} with error code: {}", task_id, code),
/// }
/// }
/// ```
///
/// # Panics
/// - Panics if parcel operations fail due to IPC errors
pub(crate) fn pause(&self, task_id: i64) -> Result<(), i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
data.write(&1u32).unwrap(); // version
data.write(&1u32).unwrap(); // task count
data.write(&task_id.to_string()).unwrap();
// Send pause request
let mut reply = remote
.send_request(interface::PAUSE, &mut data)
.map_err(|_| 13400003)?;
// Check first error code
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
// Check second error code
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
Ok(())
}
/// Resumes a paused download task.
///
/// # Arguments
/// * `task_id` - The unique identifier of the task to resume
///
/// # Returns
/// - `Ok(())` if the task was resumed successfully
/// - `Err(i32)` with the error code if resuming the task failed
///
/// # Examples
///
/// ```rust,no_run
/// use request_next::proxy::RequestProxy;
///
/// fn example(task_id: i64) {
/// let proxy = RequestProxy::get_instance();
///
/// match proxy.resume(task_id) {
/// Ok(_) => println!("Task {} resumed successfully", task_id),
/// Err(code) => eprintln!(
/// "Failed to resume task {} with error code: {}",
/// task_id, code
/// ),
/// }
/// }
/// ```
///
/// # Panics
/// - Panics if parcel operations fail due to IPC errors
pub(crate) fn resume(&self, task_id: i64) -> Result<(), i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
data.write(&1u32).unwrap(); // task count
data.write(&task_id.to_string()).unwrap();
// Send resume request
let mut reply = remote
.send_request(interface::RESUME, &mut data)
.map_err(|_| 13400003)?;
// Check first error code
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
// Check second error code
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
Ok(())
}
/// Removes a download task from the system.
///
/// # Arguments
/// * `task_id` - The unique identifier of the task to remove
///
/// # Returns
/// - `Ok(())` if the task was removed successfully
/// - `Err(i32)` with the error code if removing the task failed
///
/// # Examples
///
/// ```rust,no_run
/// use request_next::proxy::RequestProxy;
///
/// fn example(task_id: i64) {
/// let proxy = RequestProxy::get_instance();
///
/// match proxy.remove(task_id) {
/// Ok(_) => println!("Task {} removed successfully", task_id),
/// Err(code) => eprintln!(
/// "Failed to remove task {} with error code: {}",
/// task_id, code
/// ),
/// }
/// }
/// ```
///
/// # Panics
/// - Panics if parcel operations fail due to IPC errors
pub(crate) fn remove(&self, task_id: i64) -> Result<(), i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
data.write(&2u32).unwrap(); // version
data.write(&1u32).unwrap(); // task count
data.write(&task_id.to_string()).unwrap();
// Send remove request
let mut reply = remote
.send_request(interface::REMOVE, &mut data)
.map_err(|_| 13400003)?;
// Check first error code
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
// Check second error code
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
Ok(())
}
/// Stops a download task.
///
/// # Arguments
/// * `task_id` - The unique identifier of the task to stop
///
/// # Returns
/// - `Ok(())` if the task was stopped successfully
/// - `Err(i32)` with the error code if stopping the task failed
///
/// # Examples
///
/// ```rust,no_run
/// use request_next::proxy::RequestProxy;
///
/// fn example(task_id: i64) {
/// let proxy = RequestProxy::get_instance();
///
/// match proxy.stop(task_id) {
/// Ok(_) => println!("Task {} stopped successfully", task_id),
/// Err(code) => eprintln!("Failed to stop task {} with error code: {}", task_id, code),
/// }
/// }
/// ```
///
/// # Panics
/// - Panics if parcel operations fail due to IPC errors
pub(crate) fn stop(&self, task_id: i64) -> Result<(), i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
data.write(&1u32).unwrap(); // task count
data.write(&task_id.to_string()).unwrap();
// Send stop request
let mut reply = remote
.send_request(interface::STOP, &mut data)
.map_err(|_| 13400003)?;
// Check first error code
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
// Check second error code
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
Ok(())
}
/// Sets the maximum download speed for a task.
///
/// # Arguments
/// * `task_id` - The unique identifier of the task
/// * `speed` - The maximum speed limit to set
///
/// # Returns
/// - `Ok(())` if the speed limit was set successfully
/// - `Err(i32)` with the error code if setting the speed limit failed
///
/// # Examples
///
/// ```rust,no_run
/// use request_next::proxy::RequestProxy;
///
/// fn example(task_id: i64) {
/// let proxy = RequestProxy::get_instance();
/// // Set maximum speed to 1024000 bytes per second (1MB/s)
/// let max_speed = 1024000i64;
///
/// match proxy.set_max_speed(task_id, max_speed) {
/// Ok(_) => println!("Speed limit set for task {}", task_id),
/// Err(code) => eprintln!("Failed to set speed limit with error code: {}", code),
/// }
/// }
/// ```
///
/// # Panics
/// - Panics if parcel operations fail due to IPC errors
pub(crate) fn set_max_speed(&self, task_id: i64, speed: i64) -> Result<(), i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
data.write(&1u32).unwrap(); // task count
data.write(&task_id.to_string()).unwrap();
data.write(&speed).unwrap(); // maximum speed
// Send set max speed request
let mut reply = remote
.send_request(interface::SET_MAX_SPEED, &mut data)
.map_err(|_| 13400003)?;
// Check first error code
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
// Check second error code
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
Ok(())
}
}