Merge pull request #294 from ikatson/prepare-v8.0.0

Prepare v8.0.0
This commit is contained in:
Igor Katson 2025-01-06 16:56:06 +00:00 • committed by GitHub
commit a2cbf16cdd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 856 additions and 1077 deletions

972
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[package] [package]
name = "librqbit-bencode" name = "librqbit-bencode"
version = "3.0.1" version = "3.0.2"
edition = "2021" edition = "2021"
description = "Bencode serialization and deserialization using Serde" description = "Bencode serialization and deserialization using Serde"
license = "Apache-2.0" license = "Apache-2.0"
@ -16,8 +16,8 @@ sha1-ring = ["sha1w/sha1-ring"]
[dependencies] [dependencies]
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
buffers = { path = "../buffers", package = "librqbit-buffers", version = "4" } buffers = { path = "../buffers", package = "librqbit-buffers", version = "4.2" }
clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "3" } clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "3" }
anyhow = "1" anyhow = "1"
sha1w = { path = "../sha1w", default-features = false, optional = true, package = "librqbit-sha1-wrapper", version = "4" } sha1w = { path = "../sha1w", default-features = false, optional = true, package = "librqbit-sha1-wrapper", version = "4.1" }
bytes = "1.7.1" bytes = "1.7.1"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "librqbit-buffers" name = "librqbit-buffers"
version = "4.1.0" version = "4.2.0"
edition = "2021" edition = "2021"
description = "Utils to work with &[u8] and Vec<u8> in librqbit source code." description = "Utils to work with &[u8] and Vec<u8> in librqbit source code."
license = "Apache-2.0" license = "Apache-2.0"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "librqbit-dht" name = "librqbit-dht"
version = "5.1.0" version = "5.2.0"
edition = "2021" edition = "2021"
description = "DHT implementation, used in rqbit torrent client." description = "DHT implementation, used in rqbit torrent client."
license = "Apache-2.0" license = "Apache-2.0"
@ -32,7 +32,7 @@ rand = "0.8"
indexmap = "2" indexmap = "2"
dashmap = { version = "6", features = ["serde"] } dashmap = { version = "6", features = ["serde"] }
clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "3" } clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "3" }
librqbit-core = { path = "../librqbit_core", default-features = false, version = "4" } librqbit-core = { path = "../librqbit_core", default-features = false, version = "4.1" }
chrono = { version = "0.4.31", features = ["serde"] } chrono = { version = "0.4.31", features = ["serde"] }
tokio-util = "0.7.10" tokio-util = "0.7.10"
bytes = "1.7.1" bytes = "1.7.1"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "librqbit" name = "librqbit"
version = "7.1.0-beta.1" version = "8.0.0"
authors = ["Igor Katson <igor.katson@gmail.com>"] authors = ["Igor Katson <igor.katson@gmail.com>"]
edition = "2021" edition = "2021"
description = "The main library used by rqbit torrent client. The binary is just a small wrapper on top of it." description = "The main library used by rqbit torrent client. The binary is just a small wrapper on top of it."
@ -34,26 +34,30 @@ rust-tls = [
storage_middleware = ["lru"] storage_middleware = ["lru"]
storage_examples = [] storage_examples = []
tracing-subscriber-utils = ["tracing-subscriber"] tracing-subscriber-utils = ["tracing-subscriber"]
postgres = ["sqlx"] postgres = ["sqlx", "home"]
async-bt = ["async-backtrace"] async-bt = ["async-backtrace"]
watch = ["notify"] watch = ["notify"]
disable-upload = [] disable-upload = []
[dependencies] [dependencies]
sqlx = { version = "0.8.2", features = [ # sqlx and home are pinned so that we can compile on older Rusts
sqlx = { version = "=0.8.2", features = [
"runtime-tokio", "runtime-tokio",
"macros",
"postgres", "postgres",
], optional = true } ], default-features = false, optional = true }
home = { version = "=0.5.5", optional = true }
bencode = { path = "../bencode", default-features = false, package = "librqbit-bencode", version = "3" } bencode = { path = "../bencode", default-features = false, package = "librqbit-bencode", version = "3" }
tracker_comms = { path = "../tracker_comms", default-features = false, package = "librqbit-tracker-comms", version = "2" } tracker_comms = { path = "../tracker_comms", default-features = false, package = "librqbit-tracker-comms", version = "2.1" }
buffers = { path = "../buffers", package = "librqbit-buffers", version = "4.1" } buffers = { path = "../buffers", package = "librqbit-buffers", version = "4.2" }
librqbit-core = { path = "../librqbit_core", default-features = false, version = "4" } librqbit-core = { path = "../librqbit_core", default-features = false, version = "4.1" }
clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "3" } clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "3" }
peer_binary_protocol = { path = "../peer_binary_protocol", default-features = false, package = "librqbit-peer-protocol", version = "4.1" } peer_binary_protocol = { path = "../peer_binary_protocol", default-features = false, package = "librqbit-peer-protocol", version = "4.1" }
sha1w = { path = "../sha1w", default-features = false, package = "librqbit-sha1-wrapper", version = "4" } sha1w = { path = "../sha1w", default-features = false, package = "librqbit-sha1-wrapper", version = "4.1" }
dht = { path = "../dht", package = "librqbit-dht", version = "5.1.0" } dht = { path = "../dht", package = "librqbit-dht", version = "5.2.0" }
librqbit-upnp = { path = "../upnp", version = "0.1.1" } librqbit-upnp = { path = "../upnp", version = "1" }
upnp-serve = { path = "../upnp-serve", package = "librqbit-upnp-serve", default-features = false, version = "0.1.0", optional = true } upnp-serve = { path = "../upnp-serve", package = "librqbit-upnp-serve", default-features = false, version = "1", optional = true }
tokio = { version = "1", features = [ tokio = { version = "1", features = [
"macros", "macros",
@ -61,16 +65,16 @@ tokio = { version = "1", features = [
"fs", "fs",
"io-util", "io-util",
] } ] }
governor = "0.7" governor = "0.8"
console-subscriber = { version = "0.4", optional = true } console-subscriber = { version = "0.4", optional = true }
axum = { version = "0.7", optional = true } axum = { version = "0.8", optional = true }
tower-http = { version = "0.5", features = ["cors", "trace"], optional = true } tower-http = { version = "0.6", features = ["cors", "trace"], optional = true }
tokio-stream = "0.1" tokio-stream = "0.1"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
serde_urlencoded = "0.7" serde_urlencoded = "0.7"
anyhow = "1" anyhow = "1"
itertools = "0.13" itertools = "0.14"
http = "1" http = "1"
regex = "1" regex = "1"
reqwest = { version = "0.12", default-features = false, features = [ reqwest = { version = "0.12", default-features = false, features = [
@ -109,7 +113,7 @@ mime_guess = { version = "2.0.5", default-features = false }
tokio-socks = "0.5.2" tokio-socks = "0.5.2"
async-trait = "0.1.81" async-trait = "0.1.81"
async-backtrace = { version = "0.2", optional = true } async-backtrace = { version = "0.2", optional = true }
notify = { version = "6.1.1", optional = true } notify = { version = "7", optional = true }
walkdir = "2.5.0" walkdir = "2.5.0"
arc-swap = "1.7.1" arc-swap = "1.7.1"

View file

@ -17,6 +17,7 @@ use serde::{Deserialize, Serialize};
use std::io::SeekFrom; use std::io::SeekFrom;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use tokio::io::AsyncSeekExt; use tokio::io::AsyncSeekExt;
use tokio::net::TcpListener; use tokio::net::TcpListener;
@ -94,7 +95,6 @@ mod timeout {
pub struct Timeout<const DEFAULT_MS: usize, const MAX_MS: usize>(pub Duration); pub struct Timeout<const DEFAULT_MS: usize, const MAX_MS: usize>(pub Duration);
#[async_trait::async_trait]
impl<S, const DEFAULT_MS: usize, const MAX_MS: usize> axum::extract::FromRequestParts<S> impl<S, const DEFAULT_MS: usize, const MAX_MS: usize> axum::extract::FromRequestParts<S>
for Timeout<DEFAULT_MS, MAX_MS> for Timeout<DEFAULT_MS, MAX_MS>
where where
@ -456,12 +456,20 @@ impl HttpApi {
state.api_peer_stats(idx, filter).map(axum::Json) state.api_peer_stats(idx, filter).map(axum::Json)
} }
#[derive(Deserialize)]
struct StreamPathParams {
id: TorrentIdOrHash,
file_id: usize,
#[serde(rename = "filename")]
_filename: Option<Arc<str>>,
}
async fn torrent_stream_file( async fn torrent_stream_file(
State(state): State<ApiState>, State(state): State<ApiState>,
Path((idx, file_id)): Path<(TorrentIdOrHash, usize)>, Path(StreamPathParams { id, file_id, .. }): Path<StreamPathParams>,
headers: http::HeaderMap, headers: http::HeaderMap,
) -> Result<impl IntoResponse> { ) -> Result<impl IntoResponse> {
let mut stream = state.api_stream(idx, file_id)?; let mut stream = state.api_stream(id, file_id)?;
let mut status = StatusCode::OK; let mut status = StatusCode::OK;
let mut output_headers = HeaderMap::new(); let mut output_headers = HeaderMap::new();
output_headers.insert("Accept-Ranges", HeaderValue::from_static("bytes")); output_headers.insert("Accept-Ranges", HeaderValue::from_static("bytes"));
@ -489,7 +497,7 @@ impl HttpApi {
); );
} }
if let Ok(mime) = state.torrent_file_mime_type(idx, file_id) { if let Ok(mime) = state.torrent_file_mime_type(id, file_id) {
output_headers.insert( output_headers.insert(
http::header::CONTENT_TYPE, http::header::CONTENT_TYPE,
HeaderValue::from_str(mime).context("bug - invalid MIME")?, HeaderValue::from_str(mime).context("bug - invalid MIME")?,
@ -497,7 +505,7 @@ impl HttpApi {
} }
let range_header = headers.get(http::header::RANGE); let range_header = headers.get(http::header::RANGE);
trace!(torrent_id=%idx, file_id=file_id, range=?range_header, "request for HTTP stream"); trace!(torrent_id=%id, file_id=file_id, range=?range_header, "request for HTTP stream");
if let Some(range) = range_header { if let Some(range) = range_header {
let offset: Option<u64> = range let offset: Option<u64> = range
@ -619,17 +627,17 @@ impl HttpApi {
.route("/dht/table", get(dht_table)) .route("/dht/table", get(dht_table))
.route("/stats", get(session_stats)) .route("/stats", get(session_stats))
.route("/torrents", get(torrents_list)) .route("/torrents", get(torrents_list))
.route("/torrents/:id", get(torrent_details)) .route("/torrents/{id}", get(torrent_details))
.route("/torrents/:id/haves", get(torrent_haves)) .route("/torrents/{id}/haves", get(torrent_haves))
.route("/torrents/:id/stats", get(torrent_stats_v0)) .route("/torrents/{id}/stats", get(torrent_stats_v0))
.route("/torrents/:id/stats/v1", get(torrent_stats_v1)) .route("/torrents/{id}/stats/v1", get(torrent_stats_v1))
.route("/torrents/:id/peer_stats", get(peer_stats)) .route("/torrents/{id}/peer_stats", get(peer_stats))
.route("/torrents/:id/stream/:file_id", get(torrent_stream_file)) .route("/torrents/{id}/playlist", get(torrent_playlist))
.route("/torrents/:id/playlist", get(torrent_playlist))
.route("/torrents/playlist", get(global_playlist)) .route("/torrents/playlist", get(global_playlist))
.route("/torrents/resolve_magnet", post(resolve_magnet)) .route("/torrents/resolve_magnet", post(resolve_magnet))
.route("/torrents/{id}/stream/{file_id}", get(torrent_stream_file))
.route( .route(
"/torrents/:id/stream/:file_id/*filename", "/torrents/{id}/stream/{file_id}/{*filename}",
get(torrent_stream_file), get(torrent_stream_file),
); );
@ -637,12 +645,12 @@ impl HttpApi {
app = app app = app
.route("/torrents", post(torrents_post)) .route("/torrents", post(torrents_post))
.route("/torrents/limits", post(update_session_ratelimits)) .route("/torrents/limits", post(update_session_ratelimits))
.route("/torrents/:id/pause", post(torrent_action_pause)) .route("/torrents/{id}/pause", post(torrent_action_pause))
.route("/torrents/:id/start", post(torrent_action_start)) .route("/torrents/{id}/start", post(torrent_action_start))
.route("/torrents/:id/forget", post(torrent_action_forget)) .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( .route(
"/torrents/:id/update_only_files", "/torrents/{id}/update_only_files",
post(torrent_action_update_only_files), post(torrent_action_update_only_files),
); );
} }

View file

@ -15,16 +15,14 @@ use tracing::{error, error_span, info, Instrument};
use crate::{ use crate::{
create_torrent, create_torrent,
tests::test_util::{ tests::test_util::{
create_default_random_dir_with_torrents, setup_test_logging, spawn_debug_server, create_default_random_dir_with_torrents, setup_test_logging, wait_until_i_am_the_last_task,
wait_until_i_am_the_last_task, DropChecks, TestPeerMetadata, DropChecks, TestPeerMetadata,
}, },
AddTorrentOptions, AddTorrentResponse, Session, SessionOptions, SessionPersistenceConfig, AddTorrentOptions, AddTorrentResponse, Session, SessionOptions, SessionPersistenceConfig,
}; };
#[tokio::test(flavor = "multi_thread", worker_threads = 64)] #[tokio::test(flavor = "multi_thread", worker_threads = 64)]
async fn test_e2e_download() { async fn test_e2e_download() {
let dbg_srv = spawn_debug_server();
let timeout = std::env::var("E2E_TIMEOUT") let timeout = std::env::var("E2E_TIMEOUT")
.ok() .ok()
.and_then(|v| v.parse().ok()) .and_then(|v| v.parse().ok())
@ -39,8 +37,6 @@ async fn test_e2e_download() {
.context("test_e2e_download timed out") .context("test_e2e_download timed out")
.unwrap(); .unwrap();
dbg_srv.abort();
// Wait to ensure everything is dropped. // Wait to ensure everything is dropped.
wait_until_i_am_the_last_task().await.unwrap(); wait_until_i_am_the_last_task().await.unwrap();

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[package] [package]
name = "librqbit-core" name = "librqbit-core"
version = "4.0.1" version = "4.1.0"
edition = "2021" edition = "2021"
description = "Important utilities used throughout librqbit useful for working with torrents." description = "Important utilities used throughout librqbit useful for working with torrents."
license = "Apache-2.0" license = "Apache-2.0"
@ -23,10 +23,10 @@ url = { version = "2", default-features = false }
uuid = { version = "1", features = ["v4"] } uuid = { version = "1", features = ["v4"] }
parking_lot = "0.12" parking_lot = "0.12"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
buffers = { path = "../buffers", package = "librqbit-buffers", version = "4" } buffers = { path = "../buffers", package = "librqbit-buffers", version = "4.2" }
bencode = { path = "../bencode", default-features = false, package = "librqbit-bencode", version = "3.0.1" } bencode = { path = "../bencode", default-features = false, package = "librqbit-bencode", version = "3.0.1" }
clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "3" } clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "3" }
itertools = "0.13" itertools = "0.14"
directories = "5" directories = "5"
tokio-util = "0.7.10" tokio-util = "0.7.10"
data-encoding = "2.6.0" data-encoding = "2.6.0"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "librqbit-peer-protocol" name = "librqbit-peer-protocol"
version = "4.1.0" version = "4.2.0"
edition = "2021" edition = "2021"
description = "Protocol for working with torrent peers. Used in rqbit torrent client." description = "Protocol for working with torrent peers. Used in rqbit torrent client."
license = "Apache-2.0" license = "Apache-2.0"
@ -13,11 +13,11 @@ readme = "README.md"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
bincode = "1" bincode = "1"
byteorder = "1" byteorder = "1"
buffers = { path = "../buffers", package = "librqbit-buffers", version = "4.1" } buffers = { path = "../buffers", package = "librqbit-buffers", version = "4.2" }
bencode = { path = "../bencode", default-features = false, package = "librqbit-bencode", version = "3" } bencode = { path = "../bencode", default-features = false, package = "librqbit-bencode", version = "3" }
clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "3" } clone_to_owned = { path = "../clone_to_owned", package = "librqbit-clone-to-owned", version = "3" }
librqbit-core = { path = "../librqbit_core", default-features = false, version = "4" } librqbit-core = { path = "../librqbit_core", default-features = false, version = "4.1" }
bitvec = "1" bitvec = "1"
anyhow = "1" anyhow = "1"
bytes = "1.7.1" bytes = "1.7.1"
itertools = "0.13" itertools = "0.14"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "rqbit" name = "rqbit"
version = "7.1.0-beta.1" version = "8.0.0"
authors = ["Igor Katson <igor.katson@gmail.com>"] authors = ["Igor Katson <igor.katson@gmail.com>"]
edition = "2021" edition = "2021"
description = "A bittorrent command line client and server." description = "A bittorrent command line client and server."
@ -24,7 +24,7 @@ postgres = ["librqbit/postgres"]
disable-upload = ["librqbit/disable-upload"] disable-upload = ["librqbit/disable-upload"]
[dependencies] [dependencies]
librqbit = { version = "7.1.0-beta.0", path = "../librqbit", default-features = false, features = [ librqbit = { version = "8.0.0", path = "../librqbit", default-features = false, features = [
"http-api", "http-api",
"tracing-subscriber-utils", "tracing-subscriber-utils",
"upnp-serve-adapter", "upnp-serve-adapter",
@ -46,7 +46,7 @@ serde_json = "1"
size_format = "1" size_format = "1"
bytes = "1.5.0" bytes = "1.5.0"
openssl = { version = "0.10", features = ["vendored"], optional = true } openssl = { version = "0.10", features = ["vendored"], optional = true }
upnp-serve = { path = "../upnp-serve", default-features = false, version = "0.1.0", package = "librqbit-upnp-serve" } upnp-serve = { path = "../upnp-serve", default-features = false, version = "1", package = "librqbit-upnp-serve" }
libc = "0.2.158" libc = "0.2.158"
signal-hook = "0.3.17" signal-hook = "0.3.17"
tokio-util = "0.7.11" tokio-util = "0.7.11"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "librqbit-sha1-wrapper" name = "librqbit-sha1-wrapper"
version = "4.0.0" version = "4.1.0"
edition = "2018" edition = "2018"
description = "Common interface around various sha1 implementations used in rqbit torrent client." description = "Common interface around various sha1 implementations used in rqbit torrent client."
license = "Apache-2.0" license = "Apache-2.0"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "librqbit-tracker-comms" name = "librqbit-tracker-comms"
version = "2.0.0" version = "2.1.0"
edition = "2018" edition = "2018"
description = "Common interface around various sha1 implementations used in rqbit torrent client." description = "Common interface around various sha1 implementations used in rqbit torrent client."
license = "Apache-2.0" license = "Apache-2.0"
@ -15,8 +15,8 @@ tokio = "1"
anyhow = "1" anyhow = "1"
futures = "0.3" futures = "0.3"
async-stream = "0.3.5" async-stream = "0.3.5"
buffers = { path = "../buffers", package = "librqbit-buffers", version = "4" } buffers = { path = "../buffers", package = "librqbit-buffers", version = "4.2" }
librqbit-core = { path = "../librqbit_core", default-features = false, version = "4" } librqbit-core = { path = "../librqbit_core", default-features = false, version = "4.1" }
byteorder = "1.5" byteorder = "1.5"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
urlencoding = "2" urlencoding = "2"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "librqbit-upnp-serve" name = "librqbit-upnp-serve"
version = "0.1.0" version = "1.0.0"
edition = "2021" edition = "2021"
description = "Simple UPnP MediaServer implementation" description = "Simple UPnP MediaServer implementation"
license = "Apache-2.0" license = "Apache-2.0"
@ -18,7 +18,7 @@ sha1-ring = ["librqbit-sha1-wrapper/sha1-ring", "librqbit-core/sha1-ring"]
[dependencies] [dependencies]
anyhow = "1.0.86" anyhow = "1.0.86"
axum = { version = "0.7", features = ["tokio"] } axum = { version = "0.8", features = ["tokio"] }
tokio = { version = "1.39.3", features = ["full"] } tokio = { version = "1.39.3", features = ["full"] }
tracing = "0.1.40" tracing = "0.1.40"
bstr = "1.10.0" bstr = "1.10.0"
@ -26,10 +26,10 @@ serde = { version = "1", features = ["derive"] }
http = "1.1.0" http = "1.1.0"
httparse = "1.9.4" httparse = "1.9.4"
uuid = { version = "1.10.0", features = ["v4"] } uuid = { version = "1.10.0", features = ["v4"] }
librqbit-upnp = { version = "0.1", path = "../upnp", default-features = false } librqbit-upnp = { version = "1", path = "../upnp", default-features = false }
gethostname = "0.5.0" gethostname = "0.5.0"
librqbit-sha1-wrapper = { path = "../sha1w", version = "4", default-features = false } librqbit-sha1-wrapper = { path = "../sha1w", version = "4", default-features = false }
librqbit-core = { version = "4", path = "../librqbit_core", default-features = false } librqbit-core = { version = "4.1", path = "../librqbit_core", default-features = false }
mime_guess = "2.0.5" mime_guess = "2.0.5"
url = { version = "2", default-features = false } url = { version = "2", default-features = false }
parking_lot = "0.12.3" parking_lot = "0.12.3"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "librqbit-upnp" name = "librqbit-upnp"
version = "0.1.1" version = "1.0.0"
authors = ["Igor Katson <igor.katson@gmail.com>"] authors = ["Igor Katson <igor.katson@gmail.com>"]
edition = "2021" edition = "2021"
description = "Library used by rqbit torrent client to lease port forwards on the router." description = "Library used by rqbit torrent client to lease port forwards on the router."