// 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.
//! Query interface for download tasks.
//!
//! This module extends the `RequestProxy` with functionality for querying and
//! searching download tasks. It provides methods to retrieve task information,
//! mime types, and search for tasks based on various criteria.
// External dependencies
use std::time::{SystemTime, UNIX_EPOCH};
use ipc::parcel::MsgParcel;
use ipc::remote;
// Download core dependencies
use request_core::config::{Action, TaskConfig};
use request_core::filter::SearchFilter;
use request_core::info::{State, TaskInfo};
use request_core::interface;
// Local dependencies
use crate::proxy::{RequestProxy, SERVICE_TOKEN};
impl RequestProxy {
/// Queries basic information about a specific download task.
///
/// # Arguments
/// * `task_id` - Unique identifier of the task to query
///
/// # Returns
/// - `Ok(())` on success
/// - `Err(i32)` with an error code on failure
///
/// # Notes
/// This method is currently not fully implemented and contains a `todo!()`
/// placeholder.
pub(crate) fn query(&self, task_id: i64) -> Result<TaskInfo, i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
data.write(&1u32).unwrap();
data.write(&task_id.to_string()).unwrap();
let mut reply = remote
.send_request(interface::QUERY, &mut data)
.map_err(|_| 13400003)?;
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
let task_info = reply.read::<TaskInfo>().unwrap(); // task info
Ok(task_info)
}
/// Queries the MIME type of a specific download task.
///
/// # Arguments
/// * `task_id` - Unique identifier of the task to query
///
/// # Returns
/// A `Result` containing either:
/// - `Ok(String)` with the MIME type of the download task
/// - `Err(i32)` with an error code if the task doesn't exist or cannot be
/// accessed
///
/// # Examples
///
/// ```rust,no_run
/// use request_next::proxy::RequestProxy;
///
/// fn example() -> Result<(), i32> {
/// let proxy = RequestProxy::get_instance();
/// let task_id = 12345;
///
/// match proxy.query_mime_type(task_id) {
/// Ok(mime_type) => println!("Task MIME type: {}", mime_type),
/// Err(error) => println!("Failed to get MIME type: {}", error),
/// }
///
/// Ok(())
/// }
/// ```
pub(crate) fn query_mime_type(&self, task_id: i64) -> Result<String, i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
data.write(&task_id.to_string()).unwrap();
let mut reply = remote
.send_request(interface::QUERY_MIME_TYPE, &mut data)
.map_err(|_| 13400003)?;
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
let mime_type = reply.read::<String>().unwrap();
Ok(mime_type)
}
/// Retrieves detailed information about a specific download task.
///
/// # Arguments
/// * `task_id` - Unique identifier of the task to retrieve
///
/// # Returns
/// A `Result` containing either:
/// - `Ok(TaskInfo)` with detailed information about the task
/// - `Err(i32)` with an error code if the task doesn't exist or cannot be
/// accessed
///
/// # Examples
///
/// ```rust,no_run
/// use request_next::proxy::RequestProxy;
///
/// fn example() -> Result<(), i32> {
/// let proxy = RequestProxy::get_instance();
/// let task_id = 12345;
///
/// match proxy.show(task_id) {
/// Ok(task_info) => println!("Task URL: {}", task_info.url),
/// Err(error) => println!("Failed to retrieve task info: {}", error),
/// }
///
/// Ok(())
/// }
/// ```
pub(crate) fn show(&self, task_id: i64) -> Result<TaskInfo, i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
data.write(&1u32).unwrap();
data.write(&task_id.to_string()).unwrap();
let mut reply = remote
.send_request(interface::SHOW, &mut data)
.map_err(|_| 13400003)?;
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
let task_info = reply.read::<TaskInfo>().unwrap(); // task info
Ok(task_info)
}
/// Updates the last access time of a download task.
///
/// # Arguments
/// * `task_id` - Unique identifier of the task to update
/// * `token` - Authentication token for accessing the task
///
/// # Returns
/// - `Ok(())` on success
/// - `Err(i32)` with an error code on failure
///
/// # Notes
/// This method is currently not fully implemented and contains a `todo!()`
/// placeholder.
pub(crate) fn touch(&self, task_id: i64, token: String) -> Result<TaskInfo, i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
data.write(&1u32).unwrap();
data.write(&task_id.to_string()).unwrap();
data.write(&token).unwrap(); // authentication token
let mut reply = remote
.send_request(interface::TOUCH, &mut data)
.map_err(|_| 13400003)?;
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 {
return Err(code);
}
let task_info = reply.read::<TaskInfo>().unwrap(); // task info
Ok(task_info)
}
/// Searches for download tasks based on specified filter criteria.
///
/// # Arguments
/// * `filter` - Search criteria to filter tasks by bundle name, time range,
/// state, action, and mode
///
/// # Returns
/// A `Result` containing either:
/// - `Ok(Vec<String>)` with a list of matching task IDs
/// - `Err(i32)` with an error code if the search fails
///
/// # Examples
///
/// ```rust,no_run
/// use request_core::filter::SearchFilter;
/// use request_core::info::State;
/// use request_next::proxy::RequestProxy;
///
/// fn example() -> Result<(), i32> {
/// let proxy = RequestProxy::get_instance();
///
/// // Search for completed tasks
/// let filter = SearchFilter {
/// state: Some(State::Completed),
/// bundle_name: None,
/// before: None,
/// after: None,
/// action: None,
/// mode: None,
/// };
///
/// match proxy.search(filter) {
/// Ok(task_ids) => println!("Found {} completed tasks", task_ids.len()),
/// Err(error) => println!("Search failed: {}", error),
/// }
///
/// Ok(())
/// }
/// ```
pub(crate) fn search(&self, filter: SearchFilter) -> Result<Vec<String>, i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
// Serialize bundle name filter, use "*" as wildcard for None
match filter.bundle_name {
Some(ref bundle) => data.write(bundle).unwrap(),
None => data.write(&"*".to_string()).unwrap(),
}
// Serialize the filter parameters into the parcel
match filter.before {
Some(before) => data.write(&before).unwrap(),
None => match SystemTime::now().duration_since(UNIX_EPOCH) {
Ok(n) => data.write(&(n.as_millis() as i64)).unwrap(),
Err(_) => data.write(&(0i64)).unwrap(),
},
}
match filter.after {
Some(after) => data.write(&after).unwrap(),
None => match SystemTime::now().duration_since(UNIX_EPOCH) {
Ok(n) => data
.write(&(n.as_millis() as i64 - 24 * 60 * 60 * 1000))
.unwrap(),
Err(_) => data.write(&(0i64)).unwrap(),
},
}
match filter.state {
Some(state) => data.write(&(state as u32)).unwrap(),
None => data.write(&(State::Any as u32)).unwrap(),
}
match filter.action {
Some(action) => data.write(&(action as u32)).unwrap(),
None => data.write(&(2u32)).unwrap(),
}
match filter.mode {
Some(mode) => data.write(&(mode as u32)).unwrap(),
None => data.write(&02u32).unwrap(), // Default mode value
}
let mut reply = remote
.send_request(interface::SEARCH, &mut data)
.map_err(|_| 13400003)?;
// First value in reply is the number of results
let len = reply.read::<u32>().unwrap();
let mut ids = Vec::with_capacity(len as usize);
// Read each task ID from the reply
for _ in 0..len {
let id = reply.read::<String>().unwrap();
ids.push(id);
}
Ok(ids)
}
/// Retrieves a download task with authentication.
///
/// # Arguments
/// * `task_id` - Unique identifier of the task to retrieve
/// * `token` - Authentication token for accessing the task
///
/// # Returns
/// - `Ok(())` on success
/// - `Err(i32)` with an error code on failure
///
/// # Notes
/// This method is currently not fully implemented and contains a `todo!()`
/// placeholder.
pub(crate) fn get_task(&self, task_id: i64, token: Option<String>) -> Result<TaskConfig, i32> {
let remote = self.remote()?;
let mut data = MsgParcel::new();
data.write_interface_token(SERVICE_TOKEN).unwrap();
data.write(&task_id.to_string()).unwrap();
match token {
Some(t) => data.write(&t).unwrap(),
None => data.write(&"".to_string()).unwrap(),
} // authentication token
let mut reply = remote
.send_request(interface::GET_TASK, &mut data)
.map_err(|_| 13400003)?;
let code = reply.read::<i32>().unwrap(); // error code
if code != 0 && code != 5 {
return Err(code);
}
// Deserialize
let task_config = reply.read::<TaskConfig>().unwrap();
Ok(task_config)
}
}