From fc7ae3bbe54d69024a085e64007a7b3bcd0c4d4d Mon Sep 17 00:00:00 2001 From: Igor Katson Date: Wed, 28 Aug 2024 18:02:25 +0100 Subject: [PATCH 1/3] [Feature] option to disable upload --- crates/librqbit/src/peer_connection.rs | 4 ++-- crates/librqbit/src/peer_info_reader/mod.rs | 4 ++-- crates/librqbit/src/session.rs | 10 ++++++++ crates/librqbit/src/torrent_state/live/mod.rs | 23 +++++++++++-------- crates/librqbit/src/torrent_state/mod.rs | 1 + crates/rqbit/src/main.rs | 4 ++++ 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/crates/librqbit/src/peer_connection.rs b/crates/librqbit/src/peer_connection.rs index 55977de7..04a1be46 100644 --- a/crates/librqbit/src/peer_connection.rs +++ b/crates/librqbit/src/peer_connection.rs @@ -26,7 +26,7 @@ use crate::{read_buf::ReadBuf, spawn_utils::BlockingSpawner, stream_connect::Str pub trait PeerConnectionHandler { fn on_connected(&self, _connection_time: Duration) {} - fn get_have_bytes(&self) -> u64; + fn should_send_bitfield(&self) -> bool; fn serialize_bitfield_message_to_buf(&self, buf: &mut Vec) -> anyhow::Result; fn on_handshake(&self, handshake: Handshake) -> anyhow::Result<()>; fn on_extended_handshake( @@ -268,7 +268,7 @@ impl PeerConnection { .keep_alive_interval .unwrap_or_else(|| Duration::from_secs(120)); - if self.handler.get_have_bytes() > 0 { + if self.handler.should_send_bitfield() { let len = self .handler .serialize_bitfield_message_to_buf(&mut write_buf)?; diff --git a/crates/librqbit/src/peer_info_reader/mod.rs b/crates/librqbit/src/peer_info_reader/mod.rs index 6485cd0f..a22ab43f 100644 --- a/crates/librqbit/src/peer_info_reader/mod.rs +++ b/crates/librqbit/src/peer_info_reader/mod.rs @@ -148,8 +148,8 @@ struct Handler { } impl PeerConnectionHandler for Handler { - fn get_have_bytes(&self) -> u64 { - 0 + fn should_send_bitfield(&self) -> bool { + false } fn serialize_bitfield_message_to_buf(&self, _buf: &mut Vec) -> anyhow::Result { diff --git a/crates/librqbit/src/session.rs b/crates/librqbit/src/session.rs index 9c956bb7..d4f0a1ad 100644 --- a/crates/librqbit/src/session.rs +++ b/crates/librqbit/src/session.rs @@ -124,6 +124,8 @@ pub struct Session { pub(crate) stats: SessionStats, + disable_upload: bool, + // This is stored for all tasks to stop when session is dropped. _cancellation_token_drop_guard: DropGuard, } @@ -410,6 +412,8 @@ pub struct SessionOptions { // the root span to use. If not set will be None. pub root_span: Option, + + pub disable_upload: bool, } async fn create_tcp_listener( @@ -485,6 +489,10 @@ impl Session { let peer_id = opts.peer_id.unwrap_or_else(generate_peer_id); let token = opts.cancellation_token.take().unwrap_or_default(); + if opts.disable_upload { + warn!("uploading disabled"); + } + let (tcp_listener, tcp_listen_port) = if let Some(port_range) = opts.listen_port_range.clone() { let (l, p) = create_tcp_listener(port_range) @@ -618,6 +626,7 @@ impl Session { concurrent_initialize_semaphore: Arc::new(tokio::sync::Semaphore::new( opts.concurrent_init_limit.unwrap_or(3), )), + disable_upload: opts.disable_upload, }); if let Some(mut disk_write_rx) = disk_write_rx { @@ -1141,6 +1150,7 @@ impl Session { allow_overwrite: opts.overwrite, output_folder, disk_write_queue: self.disk_write_tx.clone(), + disable_upload: self.disable_upload, }, connector: self.connector.clone(), session: Arc::downgrade(self), diff --git a/crates/librqbit/src/torrent_state/live/mod.rs b/crates/librqbit/src/torrent_state/live/mod.rs index ec04115d..d5a551a7 100644 --- a/crates/librqbit/src/torrent_state/live/mod.rs +++ b/crates/librqbit/src/torrent_state/live/mod.rs @@ -173,14 +173,6 @@ impl TorrentStateLocked { } } -#[derive(Default)] -pub struct TorrentStateOptions { - #[allow(dead_code)] - pub peer_connect_timeout: Option, - #[allow(dead_code)] - pub peer_read_write_timeout: Option, -} - const FLUSH_BITV_EVERY_BYTES: u64 = 16 * 1024 * 1024; pub struct TorrentStateLive { @@ -929,11 +921,18 @@ impl<'a> PeerConnectionHandler for &'a PeerHandler { Ok(()) } - fn get_have_bytes(&self) -> u64 { - self.state.get_approx_have_bytes() + fn should_send_bitfield(&self) -> bool { + if self.state.torrent().options.disable_upload { + return false; + } + + self.state.get_approx_have_bytes() > 0 } fn should_transmit_have(&self, id: ValidPieceIndex) -> bool { + if self.state.torrent.options.disable_upload { + return false; + } let have = self .state .peers @@ -1164,6 +1163,10 @@ impl PeerHandler { } fn on_download_request(&self, request: Request) -> anyhow::Result<()> { + if self.state.torrent().options.disable_upload { + anyhow::bail!("upload disabled, but peer requested a piece") + } + let piece_index = match self.state.lengths.validate_piece_index(request.index) { Some(p) => p, None => { diff --git a/crates/librqbit/src/torrent_state/mod.rs b/crates/librqbit/src/torrent_state/mod.rs index 33a137c1..d5a08e8f 100644 --- a/crates/librqbit/src/torrent_state/mod.rs +++ b/crates/librqbit/src/torrent_state/mod.rs @@ -103,6 +103,7 @@ pub(crate) struct ManagedTorrentOptions { pub allow_overwrite: bool, pub output_folder: PathBuf, pub disk_write_queue: Option, + pub disable_upload: bool, } /// Common information about torrent shared among all possible states. diff --git a/crates/rqbit/src/main.rs b/crates/rqbit/src/main.rs index ea89913b..c24754e7 100644 --- a/crates/rqbit/src/main.rs +++ b/crates/rqbit/src/main.rs @@ -202,6 +202,9 @@ struct Opts { #[cfg(not(target_os = "windows"))] #[arg(long, env = "RQBIT_UMASK", value_parser=parse_umask)] umask: Option, + + #[arg(long, env = "RQBIT_DISABLE_UPLOAD")] + disable_upload: bool, } #[derive(Parser)] @@ -454,6 +457,7 @@ async fn async_main(opts: Opts, cancel: CancellationToken) -> anyhow::Result<()> root_span: None, fastresume: false, cancellation_token: Some(cancel.clone()), + disable_upload: opts.disable_upload, }; let stats_printer = |session: Arc| async move { From 7fda8c0a1433badb5cd20584c659c63a18c4c537 Mon Sep 17 00:00:00 2001 From: Igor Katson Date: Wed, 28 Aug 2024 18:07:53 +0100 Subject: [PATCH 2/3] Add doc for --disable-upload --- crates/rqbit/src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/rqbit/src/main.rs b/crates/rqbit/src/main.rs index c24754e7..4e37de20 100644 --- a/crates/rqbit/src/main.rs +++ b/crates/rqbit/src/main.rs @@ -203,6 +203,11 @@ struct Opts { #[arg(long, env = "RQBIT_UMASK", value_parser=parse_umask)] umask: Option, + /// Disable uploading entirely. If this is set, rqbit won't share piece availability + /// and will disconnect on download request. + /// + /// Might be useful e.g. if rqbit upload consumes all your upload bandwidth and interferes + /// with your other Internet usage. #[arg(long, env = "RQBIT_DISABLE_UPLOAD")] disable_upload: bool, } From 8379672f014827b7cfb28d9d6c6d69253cf6e6a5 Mon Sep 17 00:00:00 2001 From: Igor Katson Date: Thu, 29 Aug 2024 10:23:07 +0100 Subject: [PATCH 3/3] Add disable upload checkbox to UI --- desktop/src-tauri/Cargo.lock | 1 + desktop/src-tauri/src/config.rs | 5 +++++ desktop/src/configuration.tsx | 1 + desktop/src/configure.tsx | 10 ++++++++++ 4 files changed, 17 insertions(+) diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index 5afb0969..763e80cc 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -2044,6 +2044,7 @@ dependencies = [ "anyhow", "axum", "bstr", + "futures", "gethostname", "http 1.1.0", "httparse", diff --git a/desktop/src-tauri/src/config.rs b/desktop/src-tauri/src/config.rs index bb6dc904..6bea696f 100644 --- a/desktop/src-tauri/src/config.rs +++ b/desktop/src-tauri/src/config.rs @@ -143,6 +143,10 @@ pub struct RqbitDesktopConfigUpnp { #[serde(default)] pub struct RqbitDesktopConfig { pub default_download_location: PathBuf, + + #[serde(default)] + pub disable_upload: bool, + pub dht: RqbitDesktopConfigDht, pub tcp_listen: RqbitDesktopConfigTcpListen, pub upnp: RqbitDesktopConfigUpnp, @@ -167,6 +171,7 @@ impl Default for RqbitDesktopConfig { persistence: Default::default(), peer_opts: Default::default(), http_api: Default::default(), + disable_upload: false, } } } diff --git a/desktop/src/configuration.tsx b/desktop/src/configuration.tsx index 80f76778..93ee11ce 100644 --- a/desktop/src/configuration.tsx +++ b/desktop/src/configuration.tsx @@ -41,6 +41,7 @@ interface RqbitDesktopConfigUpnp { export interface RqbitDesktopConfig { default_download_location: PathLike; + disable_upload: boolean; dht: RqbitDesktopConfigDht; tcp_listen: RqbitDesktopConfigTcpListen; upnp: RqbitDesktopConfigUpnp; diff --git a/desktop/src/configure.tsx b/desktop/src/configure.tsx index bfe68de5..6dfc7231 100644 --- a/desktop/src/configure.tsx +++ b/desktop/src/configure.tsx @@ -210,6 +210,16 @@ export const ConfigModal: React.FC<{ onChange={handleInputChange} help="Where to download torrents by default. You can override this per torrent." /> + +