Well, it doesnt crash at least
This commit is contained in:
parent
276a1e175e
commit
efcffdd072
6 changed files with 101 additions and 21 deletions
|
|
@ -1,4 +1,4 @@
|
|||
use std::{net::SocketAddr, sync::Arc};
|
||||
use std::{collections::HashSet, net::SocketAddr, sync::Arc};
|
||||
|
||||
use anyhow::Context;
|
||||
use buffers::ByteBufOwned;
|
||||
|
|
@ -122,6 +122,18 @@ impl Api {
|
|||
Ok(Default::default())
|
||||
}
|
||||
|
||||
pub fn api_torrent_action_update_only_files(
|
||||
&self,
|
||||
idx: TorrentId,
|
||||
only_files: &HashSet<usize>,
|
||||
) -> Result<EmptyJsonResponse> {
|
||||
let handle = self.mgr_handle(idx)?;
|
||||
self.session
|
||||
.update_only_files(&handle, only_files)
|
||||
.context("error updating only_files")?;
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
pub fn api_set_rust_log(&self, new_value: String) -> Result<EmptyJsonResponse> {
|
||||
let tx = self
|
||||
.rust_log_reload_tx
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use anyhow::Context;
|
||||
use buffers::ByteBufOwned;
|
||||
use librqbit_core::{
|
||||
lengths::{ChunkInfo, Lengths, ValidPieceIndex},
|
||||
torrent_metainfo::{TorrentMetaV1Info, TorrentMetaV1Owned},
|
||||
};
|
||||
use librqbit_core::lengths::{ChunkInfo, Lengths, ValidPieceIndex};
|
||||
use peer_binary_protocol::Piece;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
|
|
|
|||
|
|
@ -181,6 +181,21 @@ impl HttpApi {
|
|||
state.api_torrent_action_delete(idx).map(axum::Json)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct UpdateOnlyFilesRequest {
|
||||
only_files: Vec<usize>,
|
||||
}
|
||||
|
||||
async fn torrent_action_update_only_files(
|
||||
State(state): State<ApiState>,
|
||||
Path(idx): Path<usize>,
|
||||
axum::Json(req): axum::Json<UpdateOnlyFilesRequest>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
state
|
||||
.api_torrent_action_update_only_files(idx, &req.only_files.into_iter().collect())
|
||||
.map(axum::Json)
|
||||
}
|
||||
|
||||
async fn set_rust_log(
|
||||
State(state): State<ApiState>,
|
||||
new_value: String,
|
||||
|
|
@ -215,7 +230,11 @@ impl HttpApi {
|
|||
.route("/torrents/:id/pause", post(torrent_action_pause))
|
||||
.route("/torrents/:id/start", post(torrent_action_start))
|
||||
.route("/torrents/:id/forget", post(torrent_action_forget))
|
||||
.route("/torrents/:id/delete", post(torrent_action_delete));
|
||||
.route("/torrents/:id/delete", post(torrent_action_delete))
|
||||
.route(
|
||||
"/torrents/:id/update_only_files",
|
||||
post(torrent_action_update_only_files),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "webui")]
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ impl SessionDatabase {
|
|||
.collect(),
|
||||
info_hash: torrent.info_hash().as_string(),
|
||||
info: torrent.info().info.clone(),
|
||||
only_files: torrent.only_files.clone(),
|
||||
only_files: torrent.only_files().clone(),
|
||||
is_paused: torrent
|
||||
.with_state(|s| matches!(s, ManagedTorrentState::Paused(_))),
|
||||
output_folder: torrent.info().out_dir.clone(),
|
||||
|
|
@ -1137,6 +1137,18 @@ impl Session {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_only_files(
|
||||
self: &Arc<Self>,
|
||||
handle: &ManagedTorrentHandle,
|
||||
only_files: &HashSet<usize>,
|
||||
) -> anyhow::Result<()> {
|
||||
let need_to_unpause = handle.update_only_files(only_files)?;
|
||||
if need_to_unpause {
|
||||
self.unpause(handle)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn tcp_listen_port(&self) -> Option<u16> {
|
||||
self.tcp_listen_port
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ impl ManagedTorrentState {
|
|||
|
||||
pub(crate) struct ManagedTorrentLocked {
|
||||
pub state: ManagedTorrentState,
|
||||
pub(crate) only_files: Option<Vec<usize>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -91,7 +92,6 @@ pub struct ManagedTorrentInfo {
|
|||
|
||||
pub struct ManagedTorrent {
|
||||
pub info: Arc<ManagedTorrentInfo>,
|
||||
pub(crate) only_files: Option<Vec<usize>>,
|
||||
locked: RwLock<ManagedTorrentLocked>,
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ impl ManagedTorrent {
|
|||
}
|
||||
|
||||
pub fn only_files(&self) -> Option<Vec<usize>> {
|
||||
self.only_files.clone()
|
||||
self.locked.read().only_files.clone()
|
||||
}
|
||||
|
||||
pub fn with_state<R>(&self, f: impl FnOnce(&ManagedTorrentState) -> R) -> R {
|
||||
|
|
@ -298,7 +298,7 @@ impl ManagedTorrent {
|
|||
ManagedTorrentState::Error(_) => {
|
||||
let initializing = Arc::new(TorrentStateInitializing::new(
|
||||
self.info.clone(),
|
||||
self.only_files.clone(),
|
||||
g.only_files.clone(),
|
||||
));
|
||||
g.state = ManagedTorrentState::Initializing(initializing.clone());
|
||||
drop(g);
|
||||
|
|
@ -407,6 +407,45 @@ impl ManagedTorrent {
|
|||
}
|
||||
.boxed()
|
||||
}
|
||||
|
||||
// Returns true if needed to unpause torrent.
|
||||
// This is just implementation detail - it's easier to pause/unpause than to tinker with internals.
|
||||
pub(crate) fn update_only_files(&self, only_files: &HashSet<usize>) -> anyhow::Result<bool> {
|
||||
if only_files.is_empty() {
|
||||
anyhow::bail!("you need to select at least one file");
|
||||
}
|
||||
let file_count = self.info().info.iter_file_lengths()?.count();
|
||||
for f in only_files.iter().copied() {
|
||||
if f >= file_count {
|
||||
anyhow::bail!("only_files contains invalid value {f}")
|
||||
}
|
||||
}
|
||||
|
||||
// if live, need to update chunk tracker
|
||||
// - if already finished: need to pause, then unpause (to reopen files etc)
|
||||
// if paused, need to update chunk tracker
|
||||
|
||||
let mut g = self.locked.write();
|
||||
let need_to_unpause = match &mut g.state {
|
||||
ManagedTorrentState::Initializing(_) => bail!("can't update initializing torrent"),
|
||||
ManagedTorrentState::Error(_) => false,
|
||||
ManagedTorrentState::None => false,
|
||||
ManagedTorrentState::Paused(p) => {
|
||||
p.update_only_files(only_files)?;
|
||||
false
|
||||
}
|
||||
ManagedTorrentState::Live(l) => {
|
||||
let mut p = l.pause()?;
|
||||
let e = p.update_only_files(only_files);
|
||||
g.state = ManagedTorrentState::Paused(p);
|
||||
e?;
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
g.only_files = Some(only_files.iter().copied().collect());
|
||||
Ok(need_to_unpause)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ManagedTorrentBuilder {
|
||||
|
|
@ -507,9 +546,9 @@ impl ManagedTorrentBuilder {
|
|||
self.only_files.clone(),
|
||||
));
|
||||
Ok(Arc::new(ManagedTorrent {
|
||||
only_files: self.only_files,
|
||||
locked: RwLock::new(ManagedTorrentLocked {
|
||||
state: ManagedTorrentState::Initializing(initializing),
|
||||
only_files: self.only_files,
|
||||
}),
|
||||
info,
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{fs::File, path::PathBuf, sync::Arc};
|
||||
use std::{collections::HashSet, fs::File, path::PathBuf, sync::Arc};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
|
|
@ -15,11 +15,13 @@ pub struct TorrentStatePaused {
|
|||
pub(crate) needed_bytes: u64,
|
||||
}
|
||||
|
||||
// impl TorrentStatePaused {
|
||||
// pub fn get_have_bytes(&self) -> u64 {
|
||||
// self.have_bytes
|
||||
// }
|
||||
// pub fn get_needed_bytes(&self) -> u64 {
|
||||
// self.needed_bytes
|
||||
// }
|
||||
// }
|
||||
impl TorrentStatePaused {
|
||||
pub(crate) fn update_only_files(&mut self, only_files: &HashSet<usize>) -> anyhow::Result<()> {
|
||||
let hn = self
|
||||
.chunk_tracker
|
||||
.update_only_files(self.info.info.iter_file_lengths()?, only_files)?;
|
||||
self.have_bytes = hn.have_bytes;
|
||||
self.needed_bytes = hn.needed_bytes;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue