Files
aria2-rust-pro/crates/aria2-rust-pro-rpc/src/dispatcher/compat_support/selection.rs
T

75 lines
2.4 KiB
Rust

use super::{BTreeSet, Digest, RequestGroup};
/// Applies a `select-file` option value to BitTorrent file selection state.
pub(in crate::dispatcher) fn apply_bt_select_file_option(
group: &mut RequestGroup,
select_file: &str,
) -> Result<(), String> {
let Some(mut bt_state) = group.bt().cloned() else {
return Ok(());
};
if bt_state.files.is_empty() {
return Ok(());
}
let selected_indexes = parse_bt_select_file_indexes(select_file, bt_state.files.len())?;
for (index, file) in bt_state.files.iter_mut().enumerate() {
file.selected = selected_indexes.contains(&(index + 1));
}
group.set_bt(bt_state);
Ok(())
}
/// Parses aria2-style `select-file` syntax into a set of selected file indexes.
pub(in crate::dispatcher) fn parse_bt_select_file_indexes(
select_file: &str,
file_count: usize,
) -> Result<BTreeSet<usize>, String> {
let mut selected = BTreeSet::new();
let trimmed = select_file.trim();
if trimmed.is_empty() {
return Err("empty value".to_owned());
}
for token in trimmed
.split(',')
.map(str::trim)
.filter(|token| !token.is_empty())
{
if let Some((start_raw, end_raw)) = token.split_once('-') {
let start = start_raw
.trim()
.parse::<usize>()
.map_err(|_| format!("invalid start index `{start_raw}`"))?;
let end = end_raw
.trim()
.parse::<usize>()
.map_err(|_| format!("invalid end index `{end_raw}`"))?;
if start == 0 || end == 0 {
return Err("indexes are 1-based".to_owned());
}
let (lo, hi) = if start <= end {
(start, end)
} else {
(end, start)
};
if hi > file_count {
return Err(format!("index {hi} out of range 1..={file_count}"));
}
for index in lo..=hi {
selected.insert(index);
}
continue;
}
let index = token
.parse::<usize>()
.map_err(|_| format!("invalid index `{token}`"))?;
if index == 0 {
return Err("indexes are 1-based".to_owned());
}
if index > file_count {
return Err(format!("index {index} out of range 1..={file_count}"));
}
selected.insert(index);
}
Ok(selected)
}