199 lines
6.1 KiB
Rust
199 lines
6.1 KiB
Rust
use super::{
|
|
BtPeerInfo, BtPeerMutationResult, BtPieceAvailabilityMutationResult, BtPieceAvailabilityUpdate,
|
|
BtPieceBlockUpdate, BtPieceMutationResult, BtRuntimeTickResult, BtTrackerInfo, CoreError,
|
|
DownloadEngine, DownloadId, Result,
|
|
};
|
|
|
|
impl DownloadEngine {
|
|
/// Replaces the full BT peer snapshot for a download.
|
|
pub fn apply_bt_peer_snapshot(
|
|
&mut self,
|
|
gid: DownloadId,
|
|
peers: Vec<BtPeerInfo>,
|
|
) -> Result<()> {
|
|
let group = self.group_mut(gid)?;
|
|
if group.bt().is_none() {
|
|
return Err(CoreError::InvalidState(
|
|
"bt runtime state is not initialized",
|
|
));
|
|
}
|
|
let _ = group.replace_bt_peer_snapshot(peers);
|
|
Ok(())
|
|
}
|
|
|
|
/// Applies an incremental BT peer update to a download.
|
|
pub fn apply_bt_peer_update(
|
|
&mut self,
|
|
gid: DownloadId,
|
|
peer: BtPeerInfo,
|
|
) -> Result<BtPeerMutationResult> {
|
|
let group = self.group_mut(gid)?;
|
|
if group.bt().is_none() {
|
|
return Err(CoreError::InvalidState(
|
|
"bt runtime state is not initialized",
|
|
));
|
|
}
|
|
Ok(group.apply_bt_peer_update(peer))
|
|
}
|
|
|
|
/// Applies an incremental BT piece availability update to a download.
|
|
pub fn apply_bt_piece_availability_update(
|
|
&mut self,
|
|
gid: DownloadId,
|
|
update: BtPieceAvailabilityUpdate,
|
|
) -> Result<BtPieceAvailabilityMutationResult> {
|
|
let group = self.group_mut(gid)?;
|
|
if group.bt().is_none() {
|
|
return Err(CoreError::InvalidState(
|
|
"bt runtime state is not initialized",
|
|
));
|
|
}
|
|
Ok(group.apply_bt_piece_availability_update(update))
|
|
}
|
|
|
|
/// Applies an incremental BT block-completion update to a download.
|
|
pub fn apply_bt_piece_block_update(
|
|
&mut self,
|
|
gid: DownloadId,
|
|
update: BtPieceBlockUpdate,
|
|
) -> Result<BtPieceMutationResult> {
|
|
let group = self.group_mut(gid)?;
|
|
if group.bt().is_none() {
|
|
return Err(CoreError::InvalidState(
|
|
"bt runtime state is not initialized",
|
|
));
|
|
}
|
|
Ok(group.apply_bt_piece_block_update(update))
|
|
}
|
|
|
|
#[expect(
|
|
clippy::too_many_arguments,
|
|
reason = "BT runtime tick mirrors the RPC-visible counters updated together by one event"
|
|
)]
|
|
/// Applies a full BT runtime tick, including byte deltas, speeds, timers, and connection count.
|
|
pub fn apply_bt_runtime_tick(
|
|
&mut self,
|
|
gid: DownloadId,
|
|
downloaded_delta: u64,
|
|
uploaded_delta: u64,
|
|
download_speed: u64,
|
|
upload_speed: u64,
|
|
share_time_delta_secs: u64,
|
|
seeding_time_delta_secs: u64,
|
|
seeding: bool,
|
|
num_connections: Option<u32>,
|
|
) -> Result<BtRuntimeTickResult> {
|
|
let group = self.group_mut(gid)?;
|
|
if group.bt().is_none() {
|
|
return Err(CoreError::InvalidState(
|
|
"bt runtime state is not initialized",
|
|
));
|
|
}
|
|
Ok(group.apply_bt_runtime_tick(
|
|
downloaded_delta,
|
|
uploaded_delta,
|
|
download_speed,
|
|
upload_speed,
|
|
share_time_delta_secs,
|
|
seeding_time_delta_secs,
|
|
seeding,
|
|
num_connections,
|
|
))
|
|
}
|
|
|
|
/// Advances BT share/seeding timers to `now_unix_secs`.
|
|
pub fn tick_bt_runtime_clock(
|
|
&mut self,
|
|
gid: DownloadId,
|
|
now_unix_secs: u64,
|
|
seeding: bool,
|
|
) -> Result<BtRuntimeTickResult> {
|
|
let group = self.group_mut(gid)?;
|
|
if group.bt().is_none() {
|
|
return Err(CoreError::InvalidState(
|
|
"bt runtime state is not initialized",
|
|
));
|
|
}
|
|
Ok(group.tick_bt_runtime_clock(now_unix_secs, seeding))
|
|
}
|
|
|
|
/// Toggles BT seeding state while preserving share-runtime accounting.
|
|
pub fn set_bt_seeding_state(
|
|
&mut self,
|
|
gid: DownloadId,
|
|
seeding: bool,
|
|
at_unix_secs: Option<u64>,
|
|
) -> Result<BtRuntimeTickResult> {
|
|
let group = self.group_mut(gid)?;
|
|
if group.bt().is_none() {
|
|
return Err(CoreError::InvalidState(
|
|
"bt runtime state is not initialized",
|
|
));
|
|
}
|
|
Ok(group.set_bt_seeding_state(seeding, at_unix_secs))
|
|
}
|
|
|
|
/// Upserts a BT tracker runtime snapshot keyed by tracker URL.
|
|
pub fn apply_bt_tracker_snapshot(
|
|
&mut self,
|
|
gid: DownloadId,
|
|
tracker_url: &str,
|
|
tracker_id: Option<String>,
|
|
seeders: Option<u32>,
|
|
leechers: Option<u32>,
|
|
) -> Result<()> {
|
|
let group = self.group_mut(gid)?;
|
|
let bt = group.bt_mut().ok_or(CoreError::InvalidState(
|
|
"bt runtime state is not initialized",
|
|
))?;
|
|
if let Some(tracker) = bt
|
|
.trackers
|
|
.iter_mut()
|
|
.find(|tracker| tracker.url == tracker_url)
|
|
{
|
|
if let Some(tracker_id) = tracker_id {
|
|
tracker.id = Some(tracker_id);
|
|
}
|
|
if seeders.is_some() {
|
|
tracker.seeders = seeders;
|
|
}
|
|
if leechers.is_some() {
|
|
tracker.leechers = leechers;
|
|
}
|
|
} else {
|
|
bt.trackers.push(BtTrackerInfo {
|
|
url: tracker_url.to_owned(),
|
|
tier: None,
|
|
id: tracker_id,
|
|
seeders,
|
|
leechers,
|
|
});
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Records BT byte deltas and timer deltas without changing live speed counters.
|
|
pub fn record_bt_runtime_tick(
|
|
&mut self,
|
|
gid: DownloadId,
|
|
downloaded_delta: u64,
|
|
uploaded_delta: u64,
|
|
share_time_delta_secs: u64,
|
|
seeding_time_delta_secs: u64,
|
|
seeding: bool,
|
|
) -> Result<()> {
|
|
let _ = self.apply_bt_runtime_tick(
|
|
gid,
|
|
downloaded_delta,
|
|
uploaded_delta,
|
|
0,
|
|
0,
|
|
share_time_delta_secs,
|
|
seeding_time_delta_secs,
|
|
seeding,
|
|
None,
|
|
)?;
|
|
Ok(())
|
|
}
|
|
}
|