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, ) -> 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 { 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 { 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 { 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, ) -> Result { 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 { 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, ) -> Result { 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, seeders: Option, leechers: Option, ) -> 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(()) } }