// 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.
//! ETS-facing type bridge for the cache download ANI crate.
//!
//! Defines the ANI-mapped enums and structs (options, download info, errors)
//! exposed to ETS, and converts between native cache download types and these
//! ETS-facing representations.
use std::collections::HashMap;
use preload_native_rlib::{CacheDownloadError, ErrorKind};
/// SSL/TLS variant to use for a cache download request.
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.SslType")]
pub enum SslType {
/// Standard TLS protocol.
TLS,
/// Transport Layer Cryptographic Protocol (Chinese national standard).
TLCP,
}
/// Cache lookup strategy for a download request.
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.CacheStrategy")]
#[derive(PartialEq)]
pub enum CacheStrategy {
/// Force a cache update by re-downloading the resource.
FORCE,
/// Download lazily, only fetching when the resource is requested.
LAZY,
}
/// Per-request retry options for a cache download.
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.RetryOptions")]
pub struct RetryOptions {
/// Maximum number of retry attempts on failure.
pub max_retry_count: Option<i32>,
}
/// Per-request timeout options for a cache download.
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.TimeoutOptions")]
pub struct TimeoutOptions {
/// Timeout in seconds for network reachability checks.
pub network_check_timeout: Option<i32>,
/// Overall HTTP request timeout in seconds.
pub http_total_timeout: Option<i32>,
}
/// Configuration options for a cache download request.
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.CacheDownloadOptions")]
pub struct CacheDownloadOptions {
/// Optional HTTP headers to send with the request.
pub headers: Option<HashMap<String, String>>,
/// Optional SSL/TLS protocol variant.
pub ssl_type: Option<SslType>,
/// Optional path to a custom CA certificate file.
pub ca_path: Option<String>,
/// Optional cache lookup strategy.
pub cache_strategy: Option<CacheStrategy>,
/// Optional per-request retry settings.
pub retry: Option<RetryOptions>,
/// Optional per-request timeout settings.
pub timeout: Option<TimeoutOptions>,
}
/// Information about the downloaded resource itself.
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.ResourceInfoInner")]
pub struct ResourceInfo {
/// Size of the downloaded resource in bytes.
pub size: i64,
}
/// Network-related information collected during the download.
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.NetworkInfoInner")]
pub struct NetworkInfo {
/// List of DNS server addresses used for resolution.
pub dns_servers: Vec<String>,
/// Resolved server IP address, if available.
pub ip: Option<String>,
}
/// Timing measurements for the phases of a download.
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.PerformanceInfoInner")]
pub struct PerformanceInfo {
/// Time spent on DNS resolution, in milliseconds.
pub dns_time: f64,
/// Time spent establishing the TCP connection, in milliseconds.
pub connect_time: f64,
/// Time spent on the TLS handshake, in milliseconds.
pub tls_time: f64,
/// Time from connection ready to first byte sent, in milliseconds.
pub first_send_time: f64,
/// Time from connection ready to first byte received, in milliseconds.
pub first_receive_time: f64,
/// Total time of the download, in milliseconds.
pub total_time: f64,
/// Time spent following redirects, in milliseconds.
pub redirect_time: f64,
}
/// Aggregated download information returned to the caller.
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.DownloadInfoInner")]
pub struct DownloadInfo {
/// Information about the downloaded resource.
pub resource: ResourceInfo,
/// Network information gathered during the download.
pub network: NetworkInfo,
/// Performance timing measurements.
pub performance: PerformanceInfo,
}
impl DownloadInfo {
/// Builds a `DownloadInfo` from the native download info structure.
pub fn from_native(native_info: preload_native_rlib::info::RustDownloadInfo) -> Self {
let ip = native_info.server_addr();
Self {
resource: ResourceInfo {
size: native_info.resource_size(),
},
network: NetworkInfo {
dns_servers: native_info.dns_servers(),
ip: if ip.is_empty() { None } else { Some(ip) },
},
performance: PerformanceInfo {
dns_time: native_info.dns_time(),
connect_time: native_info.connect_time(),
tls_time: native_info.tls_time(),
first_send_time: native_info.first_send_time(),
first_receive_time: native_info.first_recv_time(),
total_time: native_info.total_time(),
redirect_time: native_info.redirect_time(),
},
}
}
}
/// Categories of errors that can occur during a cache download.
#[derive(Clone)]
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.ErrorCode")]
pub enum ErrorCode {
/// Error that does not fit any other category.
Others = 0xFF,
/// DNS resolution failure.
Dns = 0x00,
/// TCP connection failure.
Tcp = 0x10,
/// SSL/TLS handshake or protocol failure.
Ssl = 0x20,
/// HTTP-level error (e.g. non-success status code).
Http = 0x30,
}
/// Error details reported to the caller when a cache download fails.
#[derive(Clone)]
#[ani_rs::ani(path = "@ohos.request.cacheDownload.cacheDownload.DownloadErrorInner")]
pub struct DownloadError {
/// Category of the download error.
pub error_code: ErrorCode,
/// Human-readable error message.
pub message: String,
}
impl DownloadError {
/// Converts a native cache download error into the ETS-facing form.
pub fn from_native(error: CacheDownloadError) -> Self {
Self {
error_code: match error.kind() {
ErrorKind::Dns => ErrorCode::Dns,
ErrorKind::Tcp => ErrorCode::Tcp,
ErrorKind::Ssl => ErrorCode::Ssl,
ErrorKind::Http => ErrorCode::Http,
_ => ErrorCode::Others,
},
message: error.message().to_string(),
}
}
}