Skip to main content

spill/engine/
profile.rs

1//! Per-torrent resource settings, separate from fixed protocol policy.
2mod admission;
3use std::{error::Error, fmt, io, time::Duration};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub enum AdmissionLimit {
7    Pieces,
8    PieceBytes,
9    Files,
10}
11impl fmt::Display for AdmissionLimit {
12    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13        f.write_str(match self {
14            Self::Pieces => "too many pieces",
15            Self::PieceBytes => "piece size is too large",
16            Self::Files => "too many files",
17        })
18    }
19}
20#[derive(Debug)]
21pub enum AdmissionError {
22    Metainfo(crate::protocol::metainfo::Error),
23    ResourceLimit(AdmissionLimit),
24}
25impl AdmissionError {
26    pub(in crate::engine) fn of(error: &io::Error) -> Option<&Self> {
27        error.get_ref().and_then(|e| e.downcast_ref::<Self>())
28    }
29}
30impl fmt::Display for AdmissionError {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        match self {
33            Self::Metainfo(_) => f.write_str("invalid or unsupported v1 metainfo"),
34            Self::ResourceLimit(limit) => write!(f, "unsupported torrent: {limit}"),
35        }
36    }
37}
38impl Error for AdmissionError {
39    fn source(&self) -> Option<&(dyn Error + 'static)> {
40        match self {
41            Self::Metainfo(error) => Some(error),
42            _ => None,
43        }
44    }
45}
46impl From<AdmissionError> for io::Error {
47    fn from(error: AdmissionError) -> Self {
48        Self::new(io::ErrorKind::InvalidInput, error)
49    }
50}
51
52#[derive(Clone, Copy, Debug)]
53pub struct Profile {
54    /// Per-torrent connection cap, including connecting and not-yet-joined peers.
55    pub peers: usize,
56    pub cache_bytes: usize,
57    pub write_queue_bytes: usize,
58}
59impl Default for Profile {
60    fn default() -> Self {
61        Self::DEFAULT
62    }
63}
64impl Profile {
65    pub const DEFAULT: Self = Self {
66        peers: 50,
67        cache_bytes: 16 * 1024 * 1024,
68        write_queue_bytes: 16 * 1024 * 1024,
69    };
70}
71
72pub const MAX_META: usize = 16 * 1024 * 1024;
73pub(in crate::engine) const MAX_PIECES: u32 = 1 << 20;
74pub const BLOCK_LEN: u32 = 16 * 1024;
75pub(in crate::engine) const MAX_REQUEST_QUEUE: usize = 32;
76pub(in crate::engine) const MAX_PIECE_RETRIES: u32 = 2;
77// A whole maximum-size bitfield must fit in one frame. Frames allocate only
78// their actual lengths; block/layout validation still bounds Piece messages.
79pub(in crate::engine) const MAX_FRAME_LENGTH: u32 = MAX_PIECES / 8 + 1;
80pub(in crate::engine) const MAX_PIECE_LEN: u32 = 512 * 1024 * 1024;
81pub(in crate::engine) const MAX_FILES: usize = crate::protocol::resume::MAX_FILES;
82pub(in crate::engine) const RESUME_INTERVAL: Duration = Duration::from_secs(120);
83pub(in crate::engine) const MAX_REASSIGNMENTS: u32 = 2;
84pub(in crate::engine) const PEER_IGNORED_FRAMES: u64 = 1024;
85pub(in crate::engine) const PEER_IGNORED_BYTES: u64 = 4 * 1024 * 1024;
86pub(in crate::engine) const OUTBOUND_QUEUE: usize = 64;
87pub(in crate::engine) const EVENT_QUEUE: usize = 64;
88pub(in crate::engine) const HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(15);
89pub(in crate::engine) const IDLE_TIMEOUT: Duration = Duration::from_secs(180);
90pub(in crate::engine) const FRAME_TIMEOUT: Duration = Duration::from_secs(30);
91pub(in crate::engine) const WRITE_TIMEOUT: Duration = Duration::from_secs(30);
92pub(in crate::engine) const KEEPALIVE_INTERVAL: Duration = Duration::from_secs(60);
93pub(in crate::engine) const MAX_URL_BYTES: usize = 2048;
94pub(in crate::engine) const MAX_TOTAL_URL_BYTES: usize = 16384;
95pub(in crate::engine) const TOTAL_TIMEOUT: Duration = Duration::from_secs(45);
96pub(in crate::engine) const MAX_QUEUED: usize = 128;
97pub(in crate::engine) const MAX_UPLOAD_REQUESTS: usize = 4096;
98pub(in crate::engine) const MAX_UPLOAD_READS: usize = 4;
99pub(in crate::engine) const UPLOAD_SLOTS: usize = 8;
100pub(in crate::engine) const REQUEST_TIMEOUT: Duration = Duration::from_secs(30);
101pub(in crate::engine) const HASH_CHUNK_LEN: usize = 65536;
102pub(in crate::engine) const DNS_TIMEOUT: Duration = Duration::from_secs(5);
103pub(in crate::engine) const MAX_DNS_ANSWERS: usize = 16;
104pub(in crate::engine) const MAX_WEB_SEEDS: usize = 32;
105pub(in crate::engine) const CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
106pub(in crate::engine) const STALL_RETRY_INITIAL: Duration = Duration::from_secs(1);
107pub(in crate::engine) const STALL_RETRY_MAX: Duration = Duration::from_secs(30);