use std::fmt;
const CONSERVATIVE_CONCURRENT: usize = 3;
const BALANCED_CONCURRENT: usize = 4;
const AGGRESSIVE_CONCURRENT: usize = 6;
const CONSERVATIVE_SEGMENT_SIZE: usize = 5 * 1024 * 1024;
const BALANCED_SEGMENT_SIZE: usize = 8 * 1024 * 1024;
const AGGRESSIVE_SEGMENT_SIZE: usize = 10 * 1024 * 1024;
const CONSERVATIVE_PARALLEL: usize = 4;
const BALANCED_PARALLEL: usize = 5;
const AGGRESSIVE_PARALLEL: usize = 6;
const CONSERVATIVE_BUFFER: usize = 10 * 1024 * 1024;
const BALANCED_BUFFER: usize = 20 * 1024 * 1024;
const AGGRESSIVE_BUFFER: usize = 30 * 1024 * 1024;
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
pub enum SpeedProfile {
Conservative,
#[default]
Balanced,
Aggressive,
}
impl SpeedProfile {
pub fn max_concurrent_downloads(&self) -> usize {
match self {
Self::Conservative => CONSERVATIVE_CONCURRENT,
Self::Balanced => BALANCED_CONCURRENT,
Self::Aggressive => AGGRESSIVE_CONCURRENT,
}
}
pub fn segment_size(&self) -> usize {
match self {
Self::Conservative => CONSERVATIVE_SEGMENT_SIZE,
Self::Balanced => BALANCED_SEGMENT_SIZE,
Self::Aggressive => AGGRESSIVE_SEGMENT_SIZE,
}
}
pub fn parallel_segments(&self) -> usize {
match self {
Self::Conservative => CONSERVATIVE_PARALLEL,
Self::Balanced => BALANCED_PARALLEL,
Self::Aggressive => AGGRESSIVE_PARALLEL,
}
}
pub fn max_buffer_size(&self) -> usize {
match self {
Self::Conservative => CONSERVATIVE_BUFFER,
Self::Balanced => BALANCED_BUFFER,
Self::Aggressive => AGGRESSIVE_BUFFER,
}
}
pub fn max_parallel_segments_for_large_files(&self) -> usize {
match self {
Self::Conservative => 16,
Self::Balanced => 20,
Self::Aggressive => 24,
}
}
pub fn calculate_optimal_segments(&self, file_size: u64, segment_size: u64) -> usize {
let total_segments = file_size.div_ceil(segment_size);
let file_size_mb = file_size / (1024 * 1024);
tracing::debug!(
profile = %self,
file_size_mb = file_size_mb,
segment_size = segment_size,
total_segments = total_segments,
"📥 Calculating optimal segments"
);
let max_parallel_segments = match self {
Self::Conservative => match file_size_mb {
size if size < 10 => 1,
size if size < 50 => 2,
size if size < 100 => 4,
size if size < 500 => 6,
size if size < 1000 => 8,
size if size < 2000 => 12,
_ => 16,
},
Self::Balanced => match file_size_mb {
size if size < 10 => 2,
size if size < 50 => 3,
size if size < 100 => 5,
size if size < 500 => 8,
size if size < 1000 => 12,
size if size < 2000 => 16,
_ => 20,
},
Self::Aggressive => match file_size_mb {
size if size < 10 => 3,
size if size < 50 => 5,
size if size < 100 => 6,
size if size < 500 => 10,
size if size < 1000 => 14,
size if size < 2000 => 20,
_ => 24,
},
};
let result = std::cmp::min(total_segments as usize, max_parallel_segments);
tracing::debug!(
profile = %self,
file_size_mb = file_size_mb,
max_parallel = max_parallel_segments,
optimal = result,
"📥 Optimal segments calculated"
);
result
}
pub fn max_playlist_concurrent_downloads(&self) -> usize {
match self {
Self::Conservative => 2,
Self::Balanced => 3,
Self::Aggressive => 5,
}
}
}
impl fmt::Display for SpeedProfile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Conservative => write!(f, "Conservative"),
Self::Balanced => write!(f, "Balanced"),
Self::Aggressive => write!(f, "Aggressive"),
}
}
}