mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-24 05:06:28 +00:00
build(deps): bump the dependencies group with 19 updates (#1745)
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{DEFAULT_SECRET_KEY, ENV_RPC_SECRET, IAM_POLICY_CLAIM_NAME_SA, INHERITED_POLICY_TYPE};
|
||||
use rand::{Rng, RngCore};
|
||||
use rand::{Rng, RngExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -58,7 +58,7 @@ fn encrypt<T: aes_gcm::aead::Aead>(
|
||||
use crate::error::Error;
|
||||
use aes_gcm::AeadCore;
|
||||
use aes_gcm::aead::array::Array;
|
||||
use rand::RngCore;
|
||||
use rand::Rng;
|
||||
|
||||
let mut nonce: Array<u8, <T as AeadCore>::NonceSize> = Array::default();
|
||||
rand::rng().fill_bytes(&mut nonce);
|
||||
|
||||
@@ -117,7 +117,7 @@ pub async fn create_default_key(
|
||||
|
||||
/// Create a KMS key with a specific ID (by directly writing to the key directory)
|
||||
pub async fn create_key_with_specific_id(key_dir: &str, key_id: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
use rand::RngCore;
|
||||
use rand::Rng;
|
||||
use std::collections::HashMap;
|
||||
use tokio::fs;
|
||||
|
||||
|
||||
@@ -782,7 +782,7 @@ impl<S: StorageAPI> ReplicationPool<S> {
|
||||
}
|
||||
|
||||
// Generate random duration between 0 and 1 minute
|
||||
use rand::Rng;
|
||||
use rand::RngExt;
|
||||
let duration_millis = rand::rng().random_range(0..60_000);
|
||||
let mut duration = Duration::from_millis(duration_millis);
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ use hyper_rustls::{ConfigBuilderExt, HttpsConnector};
|
||||
use hyper_util::{client::legacy::Client, client::legacy::connect::HttpConnector, rt::TokioExecutor};
|
||||
use md5::Digest;
|
||||
use md5::Md5;
|
||||
use rand::Rng;
|
||||
use rand::{Rng, RngExt};
|
||||
use rustfs_config::MAX_S3_CLIENT_RESPONSE_SIZE;
|
||||
use rustfs_rio::HashReader;
|
||||
use rustfs_utils::HashAlgorithm;
|
||||
|
||||
@@ -620,7 +620,7 @@ pub async fn load_data_usage_cache(store: &crate::set_disk::SetDisks, name: &str
|
||||
use crate::disk::{BUCKET_META_PREFIX, RUSTFS_META_BUCKET};
|
||||
use crate::store_api::{ObjectIO, ObjectOptions};
|
||||
use http::HeaderMap;
|
||||
use rand::Rng;
|
||||
use rand::RngExt;
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
use tokio::time::sleep;
|
||||
|
||||
@@ -66,7 +66,7 @@ use crate::{
|
||||
use futures::future::join_all;
|
||||
use http::HeaderMap;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::Rng as _;
|
||||
use rand::RngExt as _;
|
||||
use rustfs_common::heal_channel::{HealItemType, HealOpts};
|
||||
use rustfs_common::{GLOBAL_LOCAL_NODE_NAME, GLOBAL_RUSTFS_HOST, GLOBAL_RUSTFS_PORT};
|
||||
use rustfs_filemeta::FileInfo;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
use bytes::Bytes;
|
||||
use http::status::StatusCode;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::Rng;
|
||||
use rand::{Rng, RngExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header};
|
||||
use rand::{Rng, RngCore};
|
||||
use rand::{Rng, RngExt};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use std::io::{Error, Result};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ use aes_gcm::{
|
||||
use async_trait::async_trait;
|
||||
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
|
||||
use jiff::Zoned;
|
||||
use rand::Rng;
|
||||
use rand::RngExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -21,7 +21,7 @@ use aes_gcm::{
|
||||
aead::{Aead, KeyInit},
|
||||
};
|
||||
use chacha20poly1305::ChaCha20Poly1305;
|
||||
use rand::Rng;
|
||||
use rand::RngExt;
|
||||
|
||||
/// Trait for object encryption ciphers
|
||||
#[cfg_attr(not(test), allow(dead_code))]
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
use crate::error::{KmsError, Result};
|
||||
use async_trait::async_trait;
|
||||
use jiff::Zoned;
|
||||
use rand::RngCore;
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ categories = ["network-programming", "filesystem"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
ftps = ["libunftp", "suppaftp", "rustls"]
|
||||
ftps = ["dep:libunftp", "dep:rustls"]
|
||||
|
||||
[dependencies]
|
||||
# Core RustFS dependencies
|
||||
@@ -39,7 +39,6 @@ rustfs-utils = { workspace = true }
|
||||
# Async dependencies
|
||||
tokio = { workspace = true, features = ["fs", "io-util", "sync", "time"] }
|
||||
tracing = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
futures-util = { workspace = true }
|
||||
|
||||
# Error handling
|
||||
@@ -50,9 +49,6 @@ serde_json = { workspace = true }
|
||||
|
||||
# Utilities
|
||||
async-trait = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
tokio-util = { workspace = true, features = ["io"] }
|
||||
time = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
|
||||
@@ -61,7 +57,6 @@ s3s = { workspace = true }
|
||||
|
||||
# FTPS specific dependencies (optional)
|
||||
libunftp = { workspace = true, optional = true }
|
||||
suppaftp = { workspace = true, optional = true }
|
||||
rustls = { workspace = true, optional = true }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
|
||||
@@ -505,7 +505,7 @@ pub fn get_content_checksum(headers: &HeaderMap) -> Result<Option<Checksum>, std
|
||||
|
||||
for header in trailing_headers {
|
||||
let mut duplicates = false;
|
||||
for &checksum_type in crate::checksum::BASE_CHECKSUM_TYPES {
|
||||
for &checksum_type in BASE_CHECKSUM_TYPES {
|
||||
if let Some(key) = checksum_type.key()
|
||||
&& header.eq_ignore_ascii_case(key)
|
||||
{
|
||||
@@ -570,17 +570,17 @@ fn get_content_checksum_direct(headers: &HeaderMap) -> (ChecksumType, String) {
|
||||
if checksum_type.is_set()
|
||||
&& let Some(key) = checksum_type.key()
|
||||
{
|
||||
if let Some(value) = headers.get(key).and_then(|v| v.to_str().ok()) {
|
||||
return (checksum_type, value.to_string());
|
||||
return if let Some(value) = headers.get(key).and_then(|v| v.to_str().ok()) {
|
||||
(checksum_type, value.to_string())
|
||||
} else {
|
||||
return (ChecksumType::NONE, String::new());
|
||||
}
|
||||
(ChecksumType::NONE, String::new())
|
||||
};
|
||||
}
|
||||
return (checksum_type, String::new());
|
||||
}
|
||||
|
||||
// Check individual checksum headers
|
||||
for &ct in crate::checksum::BASE_CHECKSUM_TYPES {
|
||||
for &ct in BASE_CHECKSUM_TYPES {
|
||||
if let Some(key) = ct.key()
|
||||
&& let Some(value) = headers.get(key).and_then(|v| v.to_str().ok())
|
||||
{
|
||||
|
||||
@@ -439,6 +439,7 @@ mod tests {
|
||||
use crate::WarpReader;
|
||||
|
||||
use super::*;
|
||||
use rand::RngExt;
|
||||
use std::io::Cursor;
|
||||
use tokio::io::{AsyncReadExt, BufReader};
|
||||
|
||||
@@ -494,7 +495,6 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_compress_reader_large() {
|
||||
use rand::Rng;
|
||||
// Generate 1MB of random bytes
|
||||
let mut data = vec![0u8; 1024 * 1024 * 32];
|
||||
rand::rng().fill(&mut data[..]);
|
||||
@@ -513,7 +513,6 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_compress_reader_large_deflate() {
|
||||
use rand::Rng;
|
||||
// Generate 1MB of random bytes
|
||||
let mut data = vec![0u8; 1024 * 1024 * 3 + 512];
|
||||
rand::rng().fill(&mut data[..]);
|
||||
|
||||
@@ -487,7 +487,7 @@ mod tests {
|
||||
use crate::WarpReader;
|
||||
|
||||
use super::*;
|
||||
use rand::RngCore;
|
||||
use rand::{Rng, RngExt};
|
||||
use tokio::io::{AsyncReadExt, BufReader};
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -112,6 +112,7 @@ mod tests {
|
||||
use crate::WarpReader;
|
||||
|
||||
use super::*;
|
||||
use rand::RngExt;
|
||||
use std::io::Cursor;
|
||||
use tokio::io::{AsyncReadExt, BufReader};
|
||||
|
||||
@@ -191,7 +192,6 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_etag_reader_large_data() {
|
||||
use rand::Rng;
|
||||
// Generate 3MB random data
|
||||
let size = 3 * 1024 * 1024;
|
||||
let mut data = vec![0u8; size];
|
||||
|
||||
@@ -562,6 +562,7 @@ impl TryGetIndex for HashReader {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{DecryptReader, WarpReader, encrypt_reader};
|
||||
use rand::RngExt;
|
||||
use std::io::Cursor;
|
||||
use tokio::io::{AsyncReadExt, BufReader};
|
||||
|
||||
@@ -656,7 +657,6 @@ mod tests {
|
||||
use crate::{CompressReader, DecompressReader};
|
||||
use md5::{Digest, Md5};
|
||||
use rand::Rng;
|
||||
use rand::RngCore;
|
||||
use rustfs_utils::compress::CompressionAlgorithm;
|
||||
|
||||
// Generate 1MB random data
|
||||
|
||||
@@ -122,9 +122,9 @@ impl<R> TryGetIndex for LimitReader<R> where R: AsyncRead + Unpin + Send + Sync
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::Cursor;
|
||||
|
||||
use super::*;
|
||||
use rand::RngExt;
|
||||
use std::io::Cursor;
|
||||
use tokio::io::{AsyncReadExt, BufReader};
|
||||
|
||||
#[tokio::test]
|
||||
@@ -186,7 +186,6 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_limit_reader_large_file() {
|
||||
use rand::Rng;
|
||||
// Generate a 3MB random byte array for testing
|
||||
let size = 3 * 1024 * 1024;
|
||||
let mut data = vec![0u8; size];
|
||||
|
||||
@@ -77,11 +77,7 @@ impl Writer {
|
||||
}
|
||||
|
||||
impl AsyncWrite for Writer {
|
||||
fn poll_write(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> std::task::Poll<std::io::Result<usize>> {
|
||||
fn poll_write(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, buf: &[u8]) -> std::task::Poll<std::io::Result<usize>> {
|
||||
match self.get_mut() {
|
||||
Writer::Cursor(w) => Pin::new(w).poll_write(cx, buf),
|
||||
Writer::Http(w) => Pin::new(w).poll_write(cx, buf),
|
||||
@@ -89,14 +85,14 @@ impl AsyncWrite for Writer {
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<std::io::Result<()>> {
|
||||
fn poll_flush(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<std::io::Result<()>> {
|
||||
match self.get_mut() {
|
||||
Writer::Cursor(w) => Pin::new(w).poll_flush(cx),
|
||||
Writer::Http(w) => Pin::new(w).poll_flush(cx),
|
||||
Writer::Other(w) => Pin::new(w.as_mut()).poll_flush(cx),
|
||||
}
|
||||
}
|
||||
fn poll_shutdown(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<std::io::Result<()>> {
|
||||
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<std::io::Result<()>> {
|
||||
match self.get_mut() {
|
||||
Writer::Cursor(w) => Pin::new(w).poll_shutdown(cx),
|
||||
Writer::Http(w) => Pin::new(w).poll_shutdown(cx),
|
||||
|
||||
@@ -22,7 +22,7 @@ repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
homepage.workspace = true
|
||||
description = "RustFS Scanner provides scanning capabilities for data integrity checks, health monitoring, and storage analysis."
|
||||
keywords = ["RustFS", "scanner", "health-monitoring", "data-integrity", "storage-analysis", "Minio"]
|
||||
keywords = ["RustFS", "scanner", "health-monitoring", "data-integrity", "storage-analysis"]
|
||||
categories = ["web-programming", "development-tools", "filesystem"]
|
||||
documentation = "https://docs.rs/rustfs-scanner/latest/rustfs_scanner/"
|
||||
|
||||
@@ -47,7 +47,7 @@ rmp-serde = { workspace = true }
|
||||
rustfs-filemeta = { workspace = true }
|
||||
rustfs-madmin = { workspace = true }
|
||||
tokio-util = { workspace = true }
|
||||
rustfs-ecstore = { workspace = true }
|
||||
rustfs-ecstore = { workspace = true }
|
||||
http = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
s3s = { workspace = true }
|
||||
|
||||
@@ -502,8 +502,8 @@ impl Metrics {
|
||||
}
|
||||
|
||||
// Type aliases for compatibility with existing code
|
||||
pub type UpdateCurrentPathFn = Arc<dyn Fn(&str) -> Pin<Box<dyn std::future::Future<Output = ()> + Send>> + Send + Sync>;
|
||||
pub type CloseDiskFn = Arc<dyn Fn() -> Pin<Box<dyn std::future::Future<Output = ()> + Send>> + Send + Sync>;
|
||||
pub type UpdateCurrentPathFn = Arc<dyn Fn(&str) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>;
|
||||
pub type CloseDiskFn = Arc<dyn Fn() -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>;
|
||||
|
||||
/// Create a current path updater for tracking scan progress
|
||||
pub fn current_path_updater(disk: &str, initial: &str) -> (UpdateCurrentPathFn, CloseDiskFn) {
|
||||
@@ -519,7 +519,7 @@ pub fn current_path_updater(disk: &str, initial: &str) -> (UpdateCurrentPathFn,
|
||||
|
||||
let update_fn = {
|
||||
let tracker = Arc::clone(&tracker);
|
||||
Arc::new(move |path: &str| -> Pin<Box<dyn std::future::Future<Output = ()> + Send>> {
|
||||
Arc::new(move |path: &str| -> Pin<Box<dyn Future<Output = ()> + Send>> {
|
||||
let tracker = Arc::clone(&tracker);
|
||||
let path = path.to_string();
|
||||
Box::pin(async move {
|
||||
@@ -530,7 +530,7 @@ pub fn current_path_updater(disk: &str, initial: &str) -> (UpdateCurrentPathFn,
|
||||
|
||||
let done_fn = {
|
||||
let disk_name = disk_name.clone();
|
||||
Arc::new(move || -> Pin<Box<dyn std::future::Future<Output = ()> + Send>> {
|
||||
Arc::new(move || -> Pin<Box<dyn Future<Output = ()> + Send>> {
|
||||
let disk_name = disk_name.clone();
|
||||
Box::pin(async move {
|
||||
global_metrics().current_paths.write().await.remove(&disk_name);
|
||||
@@ -555,7 +555,7 @@ impl CloseDiskGuard {
|
||||
}
|
||||
|
||||
pub async fn close(&self) {
|
||||
(self.0)().await;
|
||||
self.0().await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,13 +86,10 @@ pub async fn read_background_heal_info(storeapi: Arc<ECStore>) -> BackgroundHeal
|
||||
|
||||
// Get last healing information
|
||||
match read_config(storeapi, &BACKGROUND_HEAL_INFO_PATH).await {
|
||||
Ok(buf) => match serde_json::from_slice::<BackgroundHealInfo>(&buf) {
|
||||
Ok(info) => info,
|
||||
Err(e) => {
|
||||
error!("Failed to unmarshal background heal info from {}: {}", &*BACKGROUND_HEAL_INFO_PATH, e);
|
||||
BackgroundHealInfo::default()
|
||||
}
|
||||
},
|
||||
Ok(buf) => serde_json::from_slice::<BackgroundHealInfo>(&buf).unwrap_or_else(|e| {
|
||||
error!("Failed to unmarshal background heal info from {}: {}", &*BACKGROUND_HEAL_INFO_PATH, e);
|
||||
BackgroundHealInfo::default()
|
||||
}),
|
||||
Err(e) => {
|
||||
// Only log if it's not a ConfigNotFound error
|
||||
if e != EcstoreError::ConfigNotFound {
|
||||
@@ -194,7 +191,7 @@ pub async fn run_data_scanner(ctx: CancellationToken, storeapi: Arc<ECStore>) ->
|
||||
|
||||
|
||||
|
||||
let (sender, receiver) = tokio::sync::mpsc::channel::<DataUsageInfo>(1);
|
||||
let (sender, receiver) = mpsc::channel::<DataUsageInfo>(1);
|
||||
let storeapi_clone = storeapi.clone();
|
||||
let ctx_clone = ctx.clone();
|
||||
tokio::spawn(async move {
|
||||
|
||||
@@ -1086,7 +1086,7 @@ pub async fn scan_data_folder(
|
||||
|
||||
// Create skip_heal flag
|
||||
let is_erasure_mode = is_erasure().await;
|
||||
let skip_heal = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(!is_erasure_mode || cache.info.skip_healing));
|
||||
let skip_heal = Arc::new(std::sync::atomic::AtomicBool::new(!is_erasure_mode || cache.info.skip_healing));
|
||||
|
||||
// Create heal_object_select flag
|
||||
let heal_object_select = if is_erasure_mode && !cache.info.skip_healing {
|
||||
@@ -1144,11 +1144,11 @@ pub async fn scan_data_folder(
|
||||
new_cache.info.last_update = Some(SystemTime::now());
|
||||
new_cache.info.next_cycle = cache.info.next_cycle;
|
||||
|
||||
(close_disk)().await;
|
||||
close_disk().await;
|
||||
Ok(new_cache.clone())
|
||||
}
|
||||
Err(e) => {
|
||||
(close_disk)().await;
|
||||
close_disk().await;
|
||||
// No useful information, return original cache
|
||||
Err(e)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
// Copyright 2024 RustFS Team
|
||||
//
|
||||
// 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.
|
||||
|
||||
use crate::scanner_folder::{ScannerItem, scan_data_folder};
|
||||
use crate::{
|
||||
DATA_USAGE_CACHE_NAME, DATA_USAGE_ROOT, DataUsageCache, DataUsageCacheInfo, DataUsageEntry, DataUsageEntryInfo,
|
||||
@@ -114,7 +128,7 @@ impl ScannerIO for ECStore {
|
||||
let results_mutex_clone = results_mutex.clone();
|
||||
let first_err_mutex_clone = first_err_mutex.clone();
|
||||
|
||||
let (tx, mut rx) = tokio::sync::mpsc::channel::<DataUsageCache>(1);
|
||||
let (tx, mut rx) = mpsc::channel::<DataUsageCache>(1);
|
||||
|
||||
// Spawn task to receive and store results
|
||||
let receiver_fut = tokio::spawn(async move {
|
||||
|
||||
@@ -165,7 +165,7 @@ pub fn is_request_error_retryable(_err: std::io::Error) -> bool {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures::StreamExt;
|
||||
use rand::Rng;
|
||||
use rand::RngExt;
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
+20
-42
@@ -12,9 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// use async_zip::tokio::read::seek::ZipFileReader;
|
||||
// use async_zip::tokio::write::ZipFileWriter;
|
||||
// use async_zip::{Compression, ZipEntryBuilder};
|
||||
use async_compression::tokio::bufread::{BzDecoder, GzipDecoder, XzDecoder, ZlibDecoder, ZstdDecoder};
|
||||
use async_compression::tokio::write::{BzEncoder, GzipEncoder, XzEncoder, ZlibEncoder, ZstdEncoder};
|
||||
use std::path::Path;
|
||||
@@ -115,6 +112,15 @@ impl CompressionFormat {
|
||||
|
||||
Ok(decoder)
|
||||
}
|
||||
/// Convert CompressionLevel to async_compression::Level
|
||||
fn convert_level(level: CompressionLevel) -> async_compression::Level {
|
||||
match level {
|
||||
CompressionLevel::Fastest => async_compression::Level::Fastest,
|
||||
CompressionLevel::Best => async_compression::Level::Best,
|
||||
CompressionLevel::Default => async_compression::Level::Default,
|
||||
CompressionLevel::Level(n) => async_compression::Level::Precise(n as i32),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create compressor
|
||||
pub fn get_encoder<W>(&self, output: W, level: CompressionLevel) -> io::Result<Box<dyn AsyncWrite + Send + Unpin>>
|
||||
@@ -125,48 +131,23 @@ impl CompressionFormat {
|
||||
|
||||
let encoder: Box<dyn AsyncWrite + Send + Unpin + 'static> = match self {
|
||||
CompressionFormat::Gzip => {
|
||||
let level = match level {
|
||||
CompressionLevel::Fastest => async_compression::Level::Fastest,
|
||||
CompressionLevel::Best => async_compression::Level::Best,
|
||||
CompressionLevel::Default => async_compression::Level::Default,
|
||||
CompressionLevel::Level(n) => async_compression::Level::Precise(n as i32),
|
||||
};
|
||||
let level = Self::convert_level(level);
|
||||
Box::new(GzipEncoder::with_quality(writer, level))
|
||||
}
|
||||
CompressionFormat::Bzip2 => {
|
||||
let level = match level {
|
||||
CompressionLevel::Fastest => async_compression::Level::Fastest,
|
||||
CompressionLevel::Best => async_compression::Level::Best,
|
||||
CompressionLevel::Default => async_compression::Level::Default,
|
||||
CompressionLevel::Level(n) => async_compression::Level::Precise(n as i32),
|
||||
};
|
||||
let level = Self::convert_level(level);
|
||||
Box::new(BzEncoder::with_quality(writer, level))
|
||||
}
|
||||
CompressionFormat::Zlib => {
|
||||
let level = match level {
|
||||
CompressionLevel::Fastest => async_compression::Level::Fastest,
|
||||
CompressionLevel::Best => async_compression::Level::Best,
|
||||
CompressionLevel::Default => async_compression::Level::Default,
|
||||
CompressionLevel::Level(n) => async_compression::Level::Precise(n as i32),
|
||||
};
|
||||
let level = Self::convert_level(level);
|
||||
Box::new(ZlibEncoder::with_quality(writer, level))
|
||||
}
|
||||
CompressionFormat::Xz => {
|
||||
let level = match level {
|
||||
CompressionLevel::Fastest => async_compression::Level::Fastest,
|
||||
CompressionLevel::Best => async_compression::Level::Best,
|
||||
CompressionLevel::Default => async_compression::Level::Default,
|
||||
CompressionLevel::Level(n) => async_compression::Level::Precise(n as i32),
|
||||
};
|
||||
let level = Self::convert_level(level);
|
||||
Box::new(XzEncoder::with_quality(writer, level))
|
||||
}
|
||||
CompressionFormat::Zstd => {
|
||||
let level = match level {
|
||||
CompressionLevel::Fastest => async_compression::Level::Fastest,
|
||||
CompressionLevel::Best => async_compression::Level::Best,
|
||||
CompressionLevel::Default => async_compression::Level::Default,
|
||||
CompressionLevel::Level(n) => async_compression::Level::Precise(n as i32),
|
||||
};
|
||||
let level = Self::convert_level(level);
|
||||
Box::new(ZstdEncoder::with_quality(writer, level))
|
||||
}
|
||||
CompressionFormat::Tar => Box::new(writer),
|
||||
@@ -189,7 +170,7 @@ impl CompressionFormat {
|
||||
pub async fn decompress<R, F>(input: R, format: CompressionFormat, mut callback: F) -> io::Result<()>
|
||||
where
|
||||
R: AsyncRead + Send + Unpin + 'static,
|
||||
F: AsyncFnMut(tokio_tar::Entry<Archive<Box<dyn AsyncRead + Send + Unpin + 'static>>>) -> std::io::Result<()> + Send + 'static,
|
||||
F: AsyncFnMut(tokio_tar::Entry<Archive<Box<dyn AsyncRead + Send + Unpin + 'static>>>) -> io::Result<()> + Send + 'static,
|
||||
{
|
||||
let decoder = format.get_decoder(input)?;
|
||||
let mut ar = Archive::new(decoder);
|
||||
@@ -258,7 +239,7 @@ impl Compressor {
|
||||
let cursor = std::io::Cursor::new(output);
|
||||
let mut encoder = self.format.get_encoder(cursor, self.level)?;
|
||||
|
||||
tokio::io::copy(&mut std::io::Cursor::new(input), &mut encoder).await?;
|
||||
io::copy(&mut std::io::Cursor::new(input), &mut encoder).await?;
|
||||
encoder.shutdown().await?;
|
||||
|
||||
// Get compressed data
|
||||
@@ -273,7 +254,7 @@ impl Compressor {
|
||||
let cursor = std::io::Cursor::new(input);
|
||||
let mut decoder = self.format.get_decoder(cursor)?;
|
||||
|
||||
tokio::io::copy(&mut decoder, &mut output).await?;
|
||||
io::copy(&mut decoder, &mut output).await?;
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
@@ -302,7 +283,7 @@ impl Decompressor {
|
||||
let mut decoder = self.format.get_decoder(input_file)?;
|
||||
let mut writer = BufWriter::new(output_file);
|
||||
|
||||
tokio::io::copy(&mut decoder, &mut writer).await?;
|
||||
io::copy(&mut decoder, &mut writer).await?;
|
||||
writer.shutdown().await?;
|
||||
|
||||
Ok(())
|
||||
@@ -538,15 +519,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_compression_format_memory_efficiency() {
|
||||
// Test memory efficiency of enum
|
||||
use std::mem;
|
||||
|
||||
// Verify enum size is reasonable
|
||||
let size = mem::size_of::<CompressionFormat>();
|
||||
let size = size_of::<CompressionFormat>();
|
||||
assert!(size <= 8, "CompressionFormat should be memory efficient, got {size} bytes");
|
||||
|
||||
// Verify Option<CompressionFormat> size
|
||||
let option_size = mem::size_of::<Option<CompressionFormat>>();
|
||||
let option_size = size_of::<Option<CompressionFormat>>();
|
||||
assert!(
|
||||
option_size <= 16,
|
||||
"Option<CompressionFormat> should be efficient, got {option_size} bytes"
|
||||
|
||||
Reference in New Issue
Block a user