Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
librqbit
https://docs.rs/librqbit/latest/
Admin
This crate provides everything necessary to download torrents.
Tokens:
241,714
Snippets:
1,458
Trust Score:
9.7
Update:
3 months ago
Context
Chat
Benchmark
77.45
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Initialize and Start Torrent Source: https://docs.rs/librqbit/latest/src/librqbit/session.rs.html?search= Configures a new managed torrent session, persists it if enabled, and starts the torrent process. ```rust let span = error_span!(parent: self.rs(), "torrent", id); let peer_opts = self.merge_peer_opts(opts.peer_opts); let metadata = Arc::new(metadata); let minfo = Arc::new(ManagedTorrentShared { id, span, info_hash, trackers: trackers.into_iter().collect(), spawner: self.spawner, peer_id: self.peer_id, storage_factory, options: ManagedTorrentOptions { force_tracker_interval: opts.force_tracker_interval, peer_connect_timeout: peer_opts.connect_timeout, peer_read_write_timeout: peer_opts.read_write_timeout, allow_overwrite: opts.overwrite, output_folder, disk_write_queue: self.disk_write_tx.clone(), ratelimits: opts.ratelimits, initial_peers: opts.initial_peers.clone().unwrap_or_default(), #[cfg(feature = "disable-upload")] _disable_upload: self._disable_upload, }, connector: self.connector.clone(), session: Arc::downgrade(self), magnet_name: name, }); let initializing = Arc::new(TorrentStateInitializing::new( minfo.clone(), metadata.clone(), only_files.clone(), minfo.storage_factory.create_and_init(&minfo, &metadata)?, false, )); let handle = Arc::new(ManagedTorrent { locked: RwLock::new(ManagedTorrentLocked { paused: opts.paused, state: ManagedTorrentState::Initializing(initializing), only_files, }), state_change_notify: Notify::new(), shared: minfo, metadata: ArcSwapOption::new(Some(metadata.clone())), }); g.add_torrent(handle.clone(), id); (handle, metadata) }; if let Some(p) = self.persistence.as_ref() { if let Err(e) = p.store(id, &managed_torrent).await { self.db.write().torrents.remove(&id); return Err(e); } } let _e = managed_torrent.shared.span.clone().entered(); managed_torrent .start(peer_rx, opts.paused) .context("error starting torrent")?; if let Some(name) = metadata.info.name.as_ref() { info!(?name, "added torrent"); } Ok(AddTorrentResponse::Added(id, managed_torrent)) ``` -------------------------------- ### Buffer Processing Example Source: https://docs.rs/librqbit/latest/librqbit/type.FileInfos.html?search=u32+-%3E+bool Demonstrates recycling a buffer to process input strings. ```rust for input in inputs { let mut buffer: Vec<&str> = storage.recycle(); buffer.extend(input.split(" ")); process(&buffer); storage = buffer.recycle(); } ``` -------------------------------- ### Start ManagedTorrent execution Source: https://docs.rs/librqbit/latest/src/librqbit/torrent_state/mod.rs.html?search=std%3A%3Avec Initializes or resumes a torrent based on its current state. Requires a peer stream if not starting in a paused state. ```rust pub(crate) fn start( self: &Arc<Self>, peer_rx: Option<PeerStream>, start_paused: bool, ) -> anyhow::Result<()> { fn _start<'a>( t: &'a Arc<ManagedTorrent>, peer_rx: Option<PeerStream>, start_paused: bool, session: Arc<Session>, g: Option<parking_lot::RwLockWriteGuard<'a, ManagedTorrentLocked>>, token: CancellationToken, ) -> anyhow::Result<()> { let mut g = g.unwrap_or_else(|| t.locked.write()); match &g.state { ManagedTorrentState::Live(_) => { bail!("torrent is already live"); } ManagedTorrentState::Initializing(init) => { let init = init.clone(); let t = t.clone(); let span = t.shared().span.clone(); let token = token.clone(); spawn_with_cancel( error_span!(parent: span.clone(), "initialize_and_start"), token.clone(), async move { let concurrent_init_semaphore = session.concurrent_initialize_semaphore.clone(); let _permit = concurrent_init_semaphore .acquire() .await .context("bug: concurrent init semaphore was closed")?; match init.check().await { Ok(paused) => { let mut g = t.locked.write(); if let ManagedTorrentState::Initializing(_) = &g.state { } else { debug!("no need to start torrent anymore, as it switched state from initilizing"); return Ok(()); } g.state = ManagedTorrentState::Paused(paused); t.state_change_notify.notify_waiters(); _start(&t, peer_rx, start_paused, session, Some(g), token) } Err(err) => { let result = anyhow::anyhow!("{:?}", err); t.locked.write().state = ManagedTorrentState::Error(err); t.state_change_notify.notify_waiters(); Err(result) } } }, ); Ok(()) } ManagedTorrentState::Paused(_) => { if start_paused { return Ok(()); } let paused = g.state.take().assert_paused(); let (tx, rx) = tokio::sync::oneshot::channel(); let live = TorrentStateLive::new(paused, tx, token.clone())?; g.state = ManagedTorrentState::Live(live.clone()); t.state_change_notify.notify_waiters(); spawn_fatal_errors_receiver(t, rx, token); if let Some(peer_rx) = peer_rx { spawn_peer_adder(&live, peer_rx); } Ok(()) } ManagedTorrentState::Error(_) => { let metadata = t.metadata.load_full().expect("TODO"); let initializing = Arc::new(TorrentStateInitializing::new( t.shared.clone(), metadata.clone(), g.only_files.clone(), t.shared .storage_factory .create_and_init(t.shared(), &metadata)?, true, )); g.state = ManagedTorrentState::Initializing(initializing.clone()); t.state_change_notify.notify_waiters(); // Recurse. _start(t, peer_rx, start_paused, session, Some(g), token) } ManagedTorrentState::None => bail!("bug: torrent is in empty state"), } } let session = self ``` -------------------------------- ### Get client name and version Source: https://docs.rs/librqbit/latest/librqbit/fn.client_name_and_version.html Returns the client name and version as a static string. ```rust pub const fn client_name_and_version() -> &'static str ``` -------------------------------- ### Incoming Peer Connection Management Source: https://docs.rs/librqbit/latest/src/librqbit/peer_connection.rs.html?search=u32+-%3E+bool Handles the initial setup and validation of an incoming peer connection. ```rust pub async fn manage_peer_incoming( &self, outgoing_chan: tokio::sync::mpsc::UnboundedReceiver<WriterRequest>, read_buf: ReadBuf, handshake: Handshake<ByteBufOwned>, mut conn: tokio::net::TcpStream, have_broadcast: tokio::sync::broadcast::Receiver<ValidPieceIndex>, ) -> anyhow::Result<()> { use tokio::io::AsyncWriteExt; let rwtimeout = self .options .read_write_timeout .unwrap_or_else(|| Duration::from_secs(10)); if handshake.info_hash != self.info_hash.0 { anyhow::bail!("wrong info hash"); } if handshake.peer_id == self.peer_id.0 { bail!("looks like we are connecting to ourselves"); } trace!( "incoming connection: id={:?}", ``` -------------------------------- ### Vector Capacity and Allocation Examples Source: https://docs.rs/librqbit/latest/librqbit/type.FileInfos.html?search=u32+-%3E+bool Demonstrates how vectors manage capacity and reallocations, including the behavior of zero-sized types. ```rust // The vector contains no items, even though it has capacity for more assert_eq!(vec.len(), 0); assert!(vec.capacity() >= 10); // These are all done without reallocating... for i in 0..10 { vec.push(i); } assert_eq!(vec.len(), 10); assert!(vec.capacity() >= 10); // ...but this may make the vector reallocate vec.push(11); assert_eq!(vec.len(), 11); assert!(vec.capacity() >= 11); // A vector of a zero-sized type will always over-allocate, since no // allocation is necessary let vec_units = Vec::<(), System>::with_capacity_in(10, System); assert_eq!(vec_units.capacity(), usize::MAX); ``` -------------------------------- ### Allocating Box with custom allocator Source: https://docs.rs/librqbit/latest/librqbit/storage/type.BoxStorageFactory.html?search= Examples of using new_in and try_new_in with the System allocator. ```rust #![feature(allocator_api)] use std::alloc::System; let five = Box::new_in(5, System); ``` ```rust #![feature(allocator_api)] use std::alloc::System; ``` -------------------------------- ### Manage Incoming Peer Connections Source: https://docs.rs/librqbit/latest/src/librqbit/peer_connection.rs.html?search= Handles the initial handshake validation and setup for an incoming peer connection. ```rust // By the time this is called: // read_buf should start with valuable data. The handshake should be removed from it. pub async fn manage_peer_incoming( &self, outgoing_chan: tokio::sync::mpsc::UnboundedReceiver<WriterRequest>, read_buf: ReadBuf, handshake: Handshake<ByteBufOwned>, mut conn: tokio::net::TcpStream, have_broadcast: tokio::sync::broadcast::Receiver<ValidPieceIndex>, ) -> anyhow::Result<()> { use tokio::io::AsyncWriteExt; let rwtimeout = self .options .read_write_timeout .unwrap_or_else(|| Duration::from_secs(10)); if handshake.info_hash != self.info_hash.0 { anyhow::bail!("wrong info hash"); } if handshake.peer_id == self.peer_id.0 { bail!("looks like we are connecting to ourselves"); } trace!( "incoming connection: id={:?}", ``` -------------------------------- ### Managing Box memory with into_non_null Source: https://docs.rs/librqbit/latest/librqbit/storage/type.BoxStorageFactory.html Examples demonstrating how to convert a Box to a NonNull pointer and perform cleanup either automatically or manually. ```rust #![feature(box_vec_non_null)] let x = Box::new(String::from("Hello")); let non_null = Box::into_non_null(x); let x = unsafe { Box::from_non_null(non_null) }; ``` ```rust #![feature(box_vec_non_null)] use std::alloc::{dealloc, Layout}; let x = Box::new(String::from("Hello")); let non_null = Box::into_non_null(x); unsafe { non_null.drop_in_place(); dealloc(non_null.as_ptr().cast::<u8>(), Layout::new::<String>()); } ``` ```rust #![feature(box_vec_non_null)] let x = Box::new(String::from("Hello")); let non_null = Box::into_non_null(x); unsafe { drop(Box::from_non_null(non_null)); } ``` -------------------------------- ### Manage Incoming Peer Connection Source: https://docs.rs/librqbit/latest/src/librqbit/peer_connection.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Handles the initial handshake validation and setup for an incoming peer connection. ```rust pub async fn manage_peer_incoming( &self, outgoing_chan: tokio::sync::mpsc::UnboundedReceiver<WriterRequest>, read_buf: ReadBuf, handshake: Handshake<ByteBufOwned>, mut conn: tokio::net::TcpStream, have_broadcast: tokio::sync::broadcast::Receiver<ValidPieceIndex>, ) -> anyhow::Result<()> { use tokio::io::AsyncWriteExt; let rwtimeout = self .options .read_write_timeout .unwrap_or_else(|| Duration::from_secs(10)); if handshake.info_hash != self.info_hash.0 { anyhow::bail!("wrong info hash"); } if handshake.peer_id == self.peer_id.0 { bail!("looks like we are connecting to ourselves"); } trace!( "incoming connection: id={:?}", ``` -------------------------------- ### Construct Box from Raw Pointer Source: https://docs.rs/librqbit/latest/librqbit/storage/type.BoxStorageFactory.html?search= Examples of creating a Box from a raw pointer using Box::from_raw. ```rust let x = Box::new(5); let ptr = Box::into_raw(x); let x = unsafe { Box::from_raw(ptr) }; ``` ```rust use std::alloc::{alloc, Layout}; unsafe { let ptr = alloc(Layout::new::<i32>()) as *mut i32; // In general .write is required to avoid attempting to destruct // the (uninitialized) previous contents of `ptr`, though for this // simple example `*ptr = 5` would have worked as well. ptr.write(5); let x = Box::from_raw(ptr); } ``` -------------------------------- ### Disk Write Channel Setup Source: https://docs.rs/librqbit/latest/src/librqbit/session.rs.html?search=u32+-%3E+bool Configures a MPSC channel for deferred disk writes based on the provided configuration. ```rust let (disk_write_tx, disk_write_rx) = opts .defer_writes_up_to .map(|mb| { const DISK_WRITE_APPROX_WORK_ITEM_SIZE: usize = CHUNK_SIZE as usize + 300; let count = mb * 1024 * 1024 / DISK_WRITE_APPROX_WORK_ITEM_SIZE; let (tx, rx) = tokio::sync::mpsc::channel(count); (Some(tx), Some(rx)) }) .unwrap_or_default(); ``` -------------------------------- ### Test reading metainfo from DHT Source: https://docs.rs/librqbit/latest/src/librqbit/dht_utils.rs.html Example test case demonstrating how to initialize a DHT builder and use read_metainfo_from_peer_receiver to fetch metainfo for a specific info hash. ```rust #[tokio::test] #[ignore] async fn read_metainfo_from_dht() { init_logging(); let info_hash = Id20::from_str("cab507494d02ebb1178b38f2e9d7be299c86b862").unwrap(); let dht = DhtBuilder::new().await.unwrap(); let peer_rx = dht.get_peers(info_hash, None); let peer_id = generate_peer_id(b"-xx1234-"); match read_metainfo_from_peer_receiver( peer_id, info_hash, Vec::new(), peer_rx, None, Arc::new(Default::default()), ) .await { ReadMetainfoResult::Found { info, .. } => dbg!(info), ReadMetainfoResult::ChannelClosed { .. } => todo!("should not have happened"), }; } ``` -------------------------------- ### pub fn librqbit_spawn Source: https://docs.rs/librqbit/latest/librqbit/fn.librqbit_spawn.html?search=std%3A%3Avec Spawns a future inside a tracing span, while logging its start, finish, and periodically logging if it is still alive. ```APIDOC ## Function: librqbit_spawn ### Description Spawns a future inside a tracing span, while logging its start, finish, and periodically logging if it is still alive. ### Signature `pub fn librqbit_spawn(_name: &str, span: Span, fut: impl Future<Output = Result<()>> + Send + 'static) -> JoinHandle<()>` ### Parameters - **_name** (&str) - The name associated with the span. - **span** (Span) - The tracing span context. - **fut** (impl Future<Output = Result<()>> + Send + 'static) - The future to be spawned. ### Returns - **JoinHandle<()>** - A handle to the spawned task. ``` -------------------------------- ### pub fn librqbit_spawn Source: https://docs.rs/librqbit/latest/librqbit/fn.librqbit_spawn.html Spawns a future inside a tracing span, while logging its start, finish, and periodically logging if it is still alive. ```APIDOC ## pub fn librqbit_spawn ### Description Spawns a future inside a tracing span, while logging its start, finish, and periodically logging if it is still alive. ### Signature `pub fn librqbit_spawn(_name: &str, span: Span, fut: impl Future<Output = Result<()>> + Send + 'static) -> JoinHandle<()>` ### Parameters - **_name** (&str) - The name associated with the spawned task. - **span** (Span) - The tracing span to associate with the future. - **fut** (impl Future<Output = Result<()>> + Send + 'static) - The future to be spawned. ### Returns - **JoinHandle<()>** - A handle to the spawned task. ``` -------------------------------- ### Vec<T> From Slice Example Source: https://docs.rs/librqbit/latest/librqbit/type.FileInfos.html?search=u32+-%3E+bool Example usage of converting a slice to a Vec<T>. ```rust ``` ``` -------------------------------- ### Configure Disk Writes and Proxy Source: https://docs.rs/librqbit/latest/src/librqbit/session.rs.html?search= Sets up deferred disk write channels and SOCKS proxy configuration based on session options. ```rust let (disk_write_tx, disk_write_rx) = opts .defer_writes_up_to .map(|mb| { const DISK_WRITE_APPROX_WORK_ITEM_SIZE: usize = CHUNK_SIZE as usize + 300; let count = mb * 1024 * 1024 / DISK_WRITE_APPROX_WORK_ITEM_SIZE; let (tx, rx) = tokio::sync::mpsc::channel(count); (Some(tx), Some(rx)) }) .unwrap_or_default(); let proxy_config = match opts.socks_proxy_url.as_ref() { Some(pu) => Some( SocksProxyConfig::parse(pu) .with_context(|| format!("error parsing proxy url {}", pu))?, ), None => None, }; ``` -------------------------------- ### StorageFactory::create_and_init Source: https://docs.rs/librqbit/latest/librqbit/storage/type.BoxStorageFactory.html Creates and initializes a new storage instance. ```APIDOC ## fn create_and_init(&self, shared: &ManagedTorrentShared, metadata: &TorrentMetadata) -> Result<Self::Storage> ### Description Creates and performs necessary initialization for a new storage instance. ### Parameters - **shared** (&ManagedTorrentShared) - Required - The shared state of the managed torrent. - **metadata** (&TorrentMetadata) - Required - The metadata of the torrent to create and initialize storage for. ### Returns - **Result<Self::Storage>** - A result containing the initialized storage instance or an error. ``` -------------------------------- ### Get Slice Length Source: https://docs.rs/librqbit/latest/librqbit/struct.ByteBuf.html?search= Returns the number of elements in the slice. ```rust let a = [1, 2, 3]; assert_eq!(a.len(), 3); ``` -------------------------------- ### Check prefix with starts_with Source: https://docs.rs/librqbit/latest/librqbit/struct.ByteBufOwned.html Verifies if a slice starts with a given prefix. ```rust let v = [10, 40, 30]; assert!(v.starts_with(&[10])); assert!(v.starts_with(&[10, 40])); assert!(v.starts_with(&v)); assert!(!v.starts_with(&[50])); assert!(!v.starts_with(&[10, 50])); ``` ```rust let v = &[10, 40, 30]; assert!(v.starts_with(&[])); let v: &[u8] = &[]; assert!(v.starts_with(&[])); ``` -------------------------------- ### Initialize Torrent Files Source: https://docs.rs/librqbit/latest/src/librqbit/storage/filesystem/fs.rs.html Initializes files for a torrent, creating directories and handling file opening based on overwrite options. ```rust fn init( &mut self, shared: &ManagedTorrentShared, metadata: &TorrentMetadata, ) -> anyhow::Result<()> { let mut files = Vec::<OpenedFile>::new(); for file_details in metadata.file_infos.iter() { let mut full_path = self.output_folder.clone(); let relative_path = &file_details.relative_filename; full_path.push(relative_path); if file_details.attrs.padding { files.push(OpenedFile::new_dummy()); continue; }; std::fs::create_dir_all(full_path.parent().context("bug: no parent")?)?; let f = if shared.options.allow_overwrite { OpenOptions::new() .create(true) .truncate(false) .read(true) .write(true) .open(&full_path) .with_context(|| format!("error opening {full_path:?} in read/write mode"))? } else { // create_new does not seem to work with read(true), so calling this twice. OpenOptions::new() .create_new(true) .write(true) .open(&full_path) .with_context(|| { format!( "error creating a new file (because allow_overwrite = false) {:?}", &full_path ) })?; OpenOptions::new().read(true).write(true).open(&full_path)? }; files.push(OpenedFile::new(f)); } self.opened_files = files; Ok(()) } } ``` -------------------------------- ### Initialize HTTP Client and Connectors Source: https://docs.rs/librqbit/latest/src/librqbit/session.rs.html?search= Builds a reqwest client with optional proxy support and initializes the stream connector. ```rust let reqwest_client = { let builder = if let Some(proxy_url) = opts.socks_proxy_url.as_ref() { let proxy = reqwest::Proxy::all(proxy_url) .context("error creating socks5 proxy for HTTP")?; reqwest::Client::builder().proxy(proxy) } else { reqwest::Client::builder() }; builder.build().context("error building HTTP(S) client")? }; let stream_connector = Arc::new(StreamConnector::from(proxy_config)); ``` -------------------------------- ### get<I> Source: https://docs.rs/librqbit/latest/librqbit/struct.ByteBufOwned.html?search=u32+-%3E+bool Returns a reference to an element or subslice depending on the type of index. ```APIDOC ## pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output> ### Description Returns a reference to an element or subslice depending on the type of index. If given a position, returns a reference to the element at that position or None if out of bounds. If given a range, returns the subslice corresponding to that range, or None if out of bounds. ``` -------------------------------- ### get<I> Source: https://docs.rs/librqbit/latest/librqbit/struct.ByteBuf.html Returns a reference to an element or subslice based on the provided index. ```APIDOC ## pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output> ### Description Returns a reference to an element or subslice depending on the type of index. If given a position, returns a reference to the element at that position or `None` if out of bounds. If given a range, returns the subslice corresponding to that range, or `None` if out of bounds. ``` -------------------------------- ### Session::new Source: https://docs.rs/librqbit/latest/librqbit/struct.Session.html Creates a new session with a default output folder. This initializes the DHT server/client and TCP listener. ```APIDOC ## Session::new(default_output_folder: PathBuf) -> BoxFuture<'static, Result<Arc<Self>>> ### Description Creates a new session with default options. The passed in folder will be used as a default unless overridden per torrent. ``` -------------------------------- ### Perform a basic torrent download Source: https://docs.rs/librqbit/latest/index.html Initializes a session and downloads a torrent from a magnet link using the tokio runtime. ```rust use librqbit::*; tokio_test::block_on(async { let session = Session::new("/tmp/where-to-download".into()).await.unwrap(); let managed_torrent_handle = session.add_torrent( AddTorrent::from_url("magnet:?xt=urn:btih:cab507494d02ebb1178b38f2e9d7be299c86b862"), None // options ).await.unwrap().into_handle().unwrap(); managed_torrent_handle.wait_until_completed().await.unwrap(); }) ``` -------------------------------- ### Blocklist and Tracker Initialization Source: https://docs.rs/librqbit/latest/src/librqbit/session.rs.html?search=u32+-%3E+bool Loads the blocklist from a URL and initializes the UDP tracker client. ```rust let blocklist: blocklist::Blocklist = if let Some(blocklist_url) = opts.blocklist_url { blocklist::Blocklist::load_from_url(&blocklist_url) .await .inspect_err(|e| warn!("failed to read blocklist: {e}")) .unwrap() } else { blocklist::Blocklist::empty() }; let udp_tracker_client = UdpTrackerClient::new(token.clone()) .await .context("error creating UDP tracker client")?; ``` -------------------------------- ### Trim ASCII Start Source: https://docs.rs/librqbit/latest/librqbit/struct.ByteBuf.html?search= Removes leading ASCII whitespace bytes from the slice. ```rust assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n"); assert_eq!(b" ".trim_ascii_start(), b""); assert_eq!(b"".trim_ascii_start(), b""); ``` -------------------------------- ### Get Last Element Source: https://docs.rs/librqbit/latest/librqbit/struct.ByteBuf.html?search= Returns the last element of the slice, or None if empty. ```rust let v = [10, 40, 30]; assert_eq!(Some(&30), v.last()); let w: &[i32] = &[]; assert_eq!(None, w.last()); ``` -------------------------------- ### Get First Element Source: https://docs.rs/librqbit/latest/librqbit/struct.ByteBuf.html?search= Returns the first element of the slice, or None if empty. ```rust let v = [10, 40, 30]; assert_eq!(Some(&10), v.first()); let w: &[i32] = &[]; assert_eq!(None, w.first()); ``` -------------------------------- ### Test Blocklist from File Source: https://docs.rs/librqbit/latest/src/librqbit/blocklist.rs.html?search=std%3A%3Avec Verifies loading a blocklist from a physical file on disk. ```rust #[tokio::test] async fn test_blocklist_from_plaintext_file() -> Result<()> { let blocklist_content = r#" # test local:192.168.1.1-192.168.1.255 localv6:2001:db8::1-2001:db8::ffff "#; // Create a temporary file let mut temp_file = tokio::fs::File::create("temp_blocklist.txt").await?; tokio::io::AsyncWriteExt::write_all(&mut temp_file, blocklist_content.as_bytes()).await?; drop(temp_file); // Close the file // Load the blocklist from the file let blocklist = Blocklist::load_from_file("temp_blocklist.txt").await?; // Verify the blocklist assert!(blocklist.is_blocked("192.168.1.1".parse().unwrap())); assert!(!blocklist.is_blocked("8.8.8.8".parse().unwrap())); assert!(blocklist.is_blocked("2001:db8::1".parse().unwrap())); assert!(!blocklist.is_blocked("2001:4860:4860::8888".parse().unwrap())); // Clean up the temporary file tokio::fs::remove_file("temp_blocklist.txt").await?; Ok(()) } ``` -------------------------------- ### FilesystemStorageFactory::create_and_init Source: https://docs.rs/librqbit/latest/librqbit/storage/filesystem/struct.FilesystemStorageFactory.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Creates and initializes a new storage instance for a torrent. ```APIDOC ## fn create_and_init(&self, shared: &ManagedTorrentShared, metadata: &TorrentMetadata) -> Result<Self::Storage> ### Description Creates and performs necessary initialization for a new storage instance. ### Parameters - **shared** (&ManagedTorrentShared) - The shared state of the managed torrent. - **metadata** (&TorrentMetadata) - The metadata associated with the torrent. ### Returns - **Result<Self::Storage>** - A result containing the initialized storage instance or an error. ``` -------------------------------- ### Torrent Action Handlers Source: https://docs.rs/librqbit/latest/src/librqbit/api.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Asynchronous methods for controlling torrent state, such as pausing and starting. ```rust pub async fn api_torrent_action_pause( &self, idx: TorrentIdOrHash, ) -> Result<EmptyJsonResponse> { let handle = self.mgr_handle(idx)?; self.session() .pause(&handle) .await .context("error pausing torrent") .with_error_status_code(StatusCode::BAD_REQUEST)?; Ok(Default::default()) } pub async fn api_torrent_action_start( &self, idx: TorrentIdOrHash, ) -> Result<EmptyJsonResponse> { let handle = self.mgr_handle(idx)?; self.session .unpause(&handle) .await .context("error unpausing torrent") ``` -------------------------------- ### rchunks Source: https://docs.rs/librqbit/latest/librqbit/struct.ByteBuf.html?search= Returns an iterator over chunk_size elements of the slice at a time, starting at the end of the slice. ```APIDOC ## pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> ### Description Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end of the slice. The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the slice, then the last chunk will not have length `chunk_size`. ### Panics Panics if `chunk_size` is zero. ``` -------------------------------- ### Get librqbit version Source: https://docs.rs/librqbit/latest/librqbit/fn.version.html Returns the current cargo version of the library as a static string. ```rust pub const fn version() -> &'static str ``` -------------------------------- ### Initialize JsonSessionPersistenceStore Source: https://docs.rs/librqbit/latest/src/librqbit/session_persistence/json.rs.html?search= Creates a new store instance and loads existing session data from the specified folder. ```rust pub async fn new(output_folder: PathBuf) -> anyhow::Result<Self> { let db_filename = output_folder.join("session.json"); tokio::fs::create_dir_all(&output_folder) .await .with_context(|| { format!( "couldn't create directory {:?} for session storage", output_folder ) })?; let db = match tokio::fs::File::open(&db_filename).await { Ok(f) => { let mut buf = Vec::new(); let mut rdr = tokio::io::BufReader::new(f); rdr.read_to_end(&mut buf).await?; serde_json::from_reader(&buf[..]).context("error deserializing session database")? } Err(e) if e.kind() == std::io::ErrorKind::NotFound => Default::default(), Err(e) => { return Err(e).context(format!("error opening session file {:?}", db_filename)) } }; Ok(Self { db_filename, output_folder, db_content: tokio::sync::RwLock::new(db), }) } ``` -------------------------------- ### Initialize Vec via as_non_null Source: https://docs.rs/librqbit/latest/librqbit/type.FileInfos.html?search=u32+-%3E+bool Demonstrates manual initialization using the experimental as_non_null API. ```rust #![feature(box_vec_non_null)] // Allocate vector big enough for 4 elements. let size = 4; let mut x: Vec<i32> = Vec::with_capacity(size); let x_ptr = x.as_non_null(); // Initialize elements via raw pointer writes, then set length. unsafe { for i in 0..size { x_ptr.add(i).write(i as i32); } x.set_len(size); } assert_eq!(&*x, &[0, 1, 2, 3]); ``` -------------------------------- ### Convert Slices and Arrays to Vec Source: https://docs.rs/librqbit/latest/librqbit/type.FileInfos.html?search=u32+-%3E+bool Examples of creating a Vec from various slice and array types. ```rust assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]); ``` ```rust assert_eq!(Vec::from(&[1, 2, 3]), vec![1, 2, 3]); ``` ```rust assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]); ``` ```rust assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]); ``` ```rust assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]); ``` -------------------------------- ### Copying Result Contents Source: https://docs.rs/librqbit/latest/librqbit/api/type.Result.html Examples of using .copied() and .cloned() on Result types containing references. ```rust let val = 12; let x: Result<&i32, i32> = Ok(&val); assert_eq!(x, Ok(&12)); let copied = x.copied(); assert_eq!(copied, Ok(12)); ``` ```rust let val = 12; let x: Result<&i32, i32> = Ok(&val); assert_eq!(x, Ok(&12)); let cloned = x.cloned(); assert_eq!(cloned, Ok(12)); ``` ```rust let mut val = 12; let x: Result<&mut i32, i32> = Ok(&mut val); assert_eq!(x, Ok(&mut 12)); let copied = x.copied(); assert_eq!(copied, Ok(12)); ``` ```rust let mut val = 12; let x: Result<&mut i32, i32> = Ok(&mut val); assert_eq!(x, Ok(&mut 12)); let cloned = x.cloned(); assert_eq!(cloned, Ok(12)); ``` -------------------------------- ### StorageFactory::create_and_init Source: https://docs.rs/librqbit/latest/librqbit/storage/type.BoxStorageFactory.html?search= Creates and initializes a new storage instance for a managed torrent. ```APIDOC ## fn create_and_init(&self, shared: &ManagedTorrentShared, metadata: &TorrentMetadata) -> Result<Self::Storage> ### Description Creates and performs necessary initialization for a new storage instance for a managed torrent. ### Parameters - **shared** (&ManagedTorrentShared) - Required - The shared state of the managed torrent. - **metadata** (&TorrentMetadata) - Required - The metadata associated with the torrent. ### Returns - **Result<Self::Storage>** - Returns the initialized storage instance or an error if the process fails. ``` -------------------------------- ### spawn Source: https://docs.rs/librqbit/latest/src/librqbit/spawn_utils.rs.html?search=std%3A%3Avec Spawns a future inside a tracing span, logging its start, finish, and periodic status. ```APIDOC ## fn spawn(_name: &str, span: tracing::Span, fut: impl std::future::Future<Output = anyhow::Result<()>> + Send + 'static) -> tokio::task::JoinHandle<()> ### Description Spawns a future inside a tracing span, while logging its start, finish, and periodically logging if it's still alive. ### Parameters - **_name** (&str) - A name for the task. - **span** (tracing::Span) - The tracing span to associate with the future. - **fut** (impl Future) - The future to execute, which must return an anyhow::Result<()>. ``` -------------------------------- ### Implement TorrentMetadata Constructor Source: https://docs.rs/librqbit/latest/src/librqbit/torrent_state/mod.rs.html Initializes TorrentMetadata by calculating lengths and file information from the torrent info. ```rust impl TorrentMetadata { pub(crate) fn new( info: TorrentMetaV1Info<ByteBufOwned>, torrent_bytes: Bytes, info_bytes: Bytes, ) -> anyhow::Result<Self> { let lengths = Lengths::from_torrent(&info)?; let file_infos = info .iter_file_details_ext(&lengths)? .map(|fd| { Ok::<_, anyhow::Error>(FileInfo { relative_filename: fd.details.filename.to_pathbuf()?, ``` -------------------------------- ### spawn Source: https://docs.rs/librqbit/latest/src/librqbit/spawn_utils.rs.html Spawns a future inside a tracing span, logging its start, finish, and periodic status. ```APIDOC ## fn spawn ### Description Spawns a future inside a tracing span, while logging its start, finish, and periodically logging if it is still alive. ### Signature `pub fn spawn(_name: &str, span: tracing::Span, fut: impl std::future::Future<Output = anyhow::Result<()>> + Send + 'static) -> tokio::task::JoinHandle<()>` ### Parameters - **_name** (&str) - The name of the task. - **span** (tracing::Span) - The tracing span to associate with the future. - **fut** (impl Future) - The future to be executed. ``` -------------------------------- ### Proxy and HTTP Client Configuration Source: https://docs.rs/librqbit/latest/src/librqbit/session.rs.html?search=u32+-%3E+bool Initializes the SOCKS proxy configuration and the reqwest HTTP client. ```rust let proxy_config = match opts.socks_proxy_url.as_ref() { Some(pu) => Some( SocksProxyConfig::parse(pu) .with_context(|| format!("error parsing proxy url {}", pu))?, ), None => None, }; let reqwest_client = { let builder = if let Some(proxy_url) = opts.socks_proxy_url.as_ref() { let proxy = reqwest::Proxy::all(proxy_url) .context("error creating socks5 proxy for HTTP")?; reqwest::Client::builder().proxy(proxy) } else { reqwest::Client::builder() }; builder.build().context("error building HTTP(S) client")? }; ``` -------------------------------- ### Create a Box with System Allocator Source: https://docs.rs/librqbit/latest/librqbit/storage/type.BoxStorageFactory.html?search= Initializes a Box with a string slice using the System allocator. ```rust let hello: Box<str, System> = Box::try_clone_from_ref_in("hello", System)?; ``` -------------------------------- ### spawn Source: https://docs.rs/librqbit/latest/src/librqbit/spawn_utils.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Spawns a future inside a tracing span, logging its start, finish, and periodic status. ```APIDOC ## fn spawn ### Description Spawns a future inside a tracing span, while logging its start, finish, and periodically logging if it's still alive. ### Signature `pub fn spawn(_name: &str, span: tracing::Span, fut: impl std::future::Future<Output = anyhow::Result<()>> + Send + 'static) -> tokio::task::JoinHandle<()>` ``` -------------------------------- ### Reverse split slice by predicate Source: https://docs.rs/librqbit/latest/librqbit/struct.ByteBufOwned.html Iterates over subslices separated by a predicate, starting from the end of the slice. ```rust let slice = [11, 22, 33, 0, 44, 55]; let mut iter = slice.rsplit(|num| *num == 0); assert_eq!(iter.next().unwrap(), &[44, 55]); assert_eq!(iter.next().unwrap(), &[11, 22, 33]); assert_eq!(iter.next(), None); ``` ```rust let v = &[0, 1, 1, 2, 3, 5, 8]; let mut it = v.rsplit(|n| *n % 2 == 0); assert_eq!(it.next().unwrap(), &[]); assert_eq!(it.next().unwrap(), &[3, 5]); assert_eq!(it.next().unwrap(), &[1, 1]); assert_eq!(it.next().unwrap(), &[]); assert_eq!(it.next(), None); ``` -------------------------------- ### API Configuration and Initialization Source: https://docs.rs/librqbit/latest/src/librqbit/api.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Defines the Api struct and options for listing torrents. ```rust #[derive(Deserialize, Default)] pub struct ApiTorrentListOpts { #[serde(default)] pub with_stats: bool, } impl Api { pub fn new( session: Arc<Session>, rust_log_reload_tx: Option<UnboundedSender<String>>, #[cfg(feature = "tracing-subscriber-utils")] line_broadcast: Option<LineBroadcast>, ) -> Self { Self { session, rust_log_reload_tx, #[cfg(feature = "tracing-subscriber-utils")] line_broadcast, } } pub fn session(&self) -> &Arc<Session> { &self.session } ``` -------------------------------- ### Get Remaining Bytes Source: https://docs.rs/librqbit/latest/src/librqbit/chunk_tracker.rs.html?search= Returns the total number of bytes still needed to complete the download. ```rust pub fn get_remaining_bytes(&self) -> u64 { self.hns.needed_bytes } ``` -------------------------------- ### Session::new Source: https://docs.rs/librqbit/latest/librqbit/struct.Session.html?search= Creates a new session with default options. ```APIDOC ## Session::new ### Description Creates a new session with default options. The passed in folder will be used as a default unless overridden per torrent. ### Signature `pub fn new(default_output_folder: PathBuf) -> BoxFuture<'static, Result<Arc<Self>>>` ``` -------------------------------- ### Manual Blocklist Management Source: https://docs.rs/librqbit/latest/src/librqbit/blocklist.rs.html Demonstrates creating an empty blocklist or manually defining IP ranges. ```rust #[test] fn test_blocklist_empty() { let blocklist = Blocklist::empty(); assert!(!blocklist.is_blocked("127.0.0.1".parse().unwrap())); assert!(!blocklist.is_blocked("::1".parse().unwrap())); } #[test] fn test_manual_ranges() { // Add IPv4 range let start_v4: IpAddr = "192.168.0.0".parse().unwrap(); let end_v4: IpAddr = "192.168.255.255".parse().unwrap(); let ipv4_range = start_v4..end_v4; // Add IPv6 range let start_v6: IpAddr = "2001:db8::".parse().unwrap(); let end_v6: IpAddr = "2001:db8::ffff".parse().unwrap(); let ipv6_range = start_v6..end_v6; let blocklist = Blocklist::new(vec![ipv4_range, ipv6_range]); // Test IPv4 addresses assert!(blocklist.is_blocked("192.168.1.1".parse().unwrap())); assert!(!blocklist.is_blocked("10.0.0.1".parse().unwrap())); // Test IPv6 addresses assert!(blocklist.is_blocked("2001:db8::1".parse().unwrap())); assert!(!blocklist.is_blocked("2001:db9::1".parse().unwrap())); } ``` -------------------------------- ### Leaking Box memory Source: https://docs.rs/librqbit/latest/librqbit/storage/type.BoxStorageFactory.html?search= Examples of consuming a Box to return a static mutable reference for long-lived data. ```rust let x = Box::new(41); let static_ref: &'static mut usize = Box::leak(x); *static_ref += 1; assert_eq!(*static_ref, 42); ``` ```rust let x = vec![1, 2, 3].into_boxed_slice(); let static_ref = Box::leak(x); static_ref[0] = 4; assert_eq!(*static_ref, [4, 2, 3]); ``` -------------------------------- ### TorrentStorage::take Source: https://docs.rs/librqbit/latest/librqbit/storage/type.BoxStorageFactory.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Replaces the current storage with a dummy and returns a new storage instance. ```APIDOC ## take() -> Result<Box<dyn TorrentStorage>> ### Description Used to invalidate the current storage object, for example when pausing a torrent. ``` -------------------------------- ### Construct Box from NonNull Pointer Source: https://docs.rs/librqbit/latest/librqbit/storage/type.BoxStorageFactory.html?search= Examples of creating a Box from a NonNull pointer using Box::from_non_null. ```rust #![feature(box_vec_non_null)] let x = Box::new(5); let non_null = Box::into_non_null(x); let x = unsafe { Box::from_non_null(non_null) }; ``` ```rust #![feature(box_vec_non_null)] use std::alloc::{alloc, Layout}; use std::ptr::NonNull; unsafe { let non_null = NonNull::new(alloc(Layout::new::<i32>()).cast::<i32>()) .expect("allocation failed"); // In general .write is required to avoid attempting to destruct // the (uninitialized) previous contents of `non_null`. non_null.write(5); let x = Box::from_non_null(non_null); } ``` -------------------------------- ### Initialize Session Source: https://docs.rs/librqbit/latest/src/librqbit/session.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Methods for creating a new session instance with default or custom options. ```rust impl Session { /// Create a new session with default options. /// The passed in folder will be used as a default unless overriden per torrent. /// It will run a DHT server/client, a TCP listener and . #[inline(never)] pub fn new(default_output_folder: PathBuf) -> BoxFuture<'static, anyhow::Result<Arc<Self>>> { Self::new_with_opts(default_output_folder, SessionOptions::default()) } pub fn cancellation_token(&self) -> &CancellationToken { &self.cancellation_token } /// Create a new session with options. #[inline(never)] pub fn new_with_opts( default_output_folder: PathBuf, mut opts: SessionOptions, ) -> BoxFuture<'static, anyhow::Result<Arc<Self>>> { async move { let peer_id = opts .peer_id .unwrap_or_else(|| generate_azereus_style(*b"rQ", crate_version!())); let token = opts.cancellation_token.take().unwrap_or_default(); #[cfg(feature = "disable-upload")] 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) .await .context("error listening on TCP")?; info!("Listening on 0.0.0.0:{p} for incoming peer connections"); (Some(l), Some(p)) } else { (None, None) }; let dht = if opts.disable_dht { None } else { let dht = if opts.disable_dht_persistence { DhtBuilder::with_config(DhtConfig { cancellation_token: Some(token.child_token()), ..Default::default() }) .await .context("error initializing DHT")? } else { let pdht_config = opts.dht_config.take().unwrap_or_default(); PersistentDht::create(Some(pdht_config), Some(token.clone())) .await .context("error initializing persistent DHT")? }; Some(dht) }; let peer_opts = opts.peer_opts.unwrap_or_default(); async fn persistence_factory( opts: &SessionOptions, ) -> anyhow::Result<( Option<Arc<dyn SessionPersistenceStore>>, Arc<dyn BitVFactory>, )> { ```