use super::{Networking, RunPolicy, RuntimeOptions, TorrentHandle, TorrentOptions};
use crate::engine::{profile::Profile, provisioning::FileStorage, storage::writer::Writer};
use crate::protocol::metainfo::OwnedMetainfo;
use std::{io, net::SocketAddr, sync::Arc, time::Duration};
use tokio::sync::Semaphore;
impl TorrentOptions {
pub fn new(metainfo: OwnedMetainfo, profile: Profile) -> Self {
Self {
settings: Default::default(),
profile,
metainfo,
storage: None,
resume: None,
checkpoint: Box::new(|_| Ok(())),
completed_announce: None,
announce_checkpoint: Arc::new(|_| Ok(())),
peers: Vec::new(),
dht: None,
run: RunPolicy::Persistent,
log_peer_endpoints: false,
no_progress_timeout: Duration::from_secs(60),
diagnostics: false,
}
}
pub fn settings(mut self, settings: crate::engine::settings::TorrentSettings) -> Self {
self.settings = settings;
self
}
pub fn storage(mut self, storage: FileStorage) -> Self {
self.storage = Some(storage);
self
}
pub fn resume(mut self, resume: Option<Vec<u8>>) -> Self {
self.resume = resume;
self
}
pub fn on_checkpoint(
mut self,
checkpoint: impl Fn(Vec<u8>) -> io::Result<()> + Send + Sync + 'static,
) -> Self {
self.checkpoint = Box::new(checkpoint);
self
}
pub fn completion_announce(
mut self,
saved: Option<bool>,
checkpoint: impl Fn(bool) -> io::Result<()> + Send + Sync + 'static,
) -> Self {
self.completed_announce = saved;
self.announce_checkpoint = Arc::new(checkpoint);
self
}
pub fn peers(mut self, peers: Vec<SocketAddr>) -> Self {
self.peers = peers;
self
}
pub fn dht(mut self, dht: Option<crate::engine::session::dht::Handle>) -> Self {
self.dht = dht;
self
}
pub fn diagnostics(mut self, enabled: bool) -> Self {
self.diagnostics = enabled;
self
}
pub fn run(mut self, run: RunPolicy) -> Self {
self.run = run;
self
}
pub(in crate::engine) fn spawn_session(
mut self,
bandwidth: crate::engine::bandwidth::Throttle,
networking: Networking,
rechecks: Arc<Semaphore>,
) -> io::Result<TorrentHandle> {
if self.metainfo.is_private() {
self.settings.dht = false;
self.settings.pex = false;
}
let selection = if self.settings.file_priorities.is_empty() {
crate::engine::selection::FileSelection::all(self.metainfo.layout())
} else {
crate::engine::selection::FileSelection::new(
self.metainfo.layout(),
&self.settings.file_priorities,
)?
};
let peer_id = crate::engine::identity::generate_peer_id()?;
let storage = self
.storage
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "storage is required"))?;
let writer = Writer::new_with_recheck(
storage,
self.metainfo.clone(),
self.profile,
matches!(self.run, RunPolicy::Recheck),
self.resume,
self.checkpoint,
rechecks,
)?;
let (reannounce, announce_requests) = tokio::sync::watch::channel(());
let options = RuntimeOptions {
reannounce: announce_requests,
completed_announce: self.completed_announce,
announce_checkpoint: self.announce_checkpoint,
dht: self.dht.filter(|_| self.settings.dht),
settings: self.settings,
metainfo: self.metainfo,
profile: self.profile,
peers: self.peers,
run: self.run,
log_peer_endpoints: self.log_peer_endpoints,
no_progress_timeout: self.no_progress_timeout,
diagnostics: self.diagnostics,
selection,
peer_id,
bandwidth,
};
Ok(TorrentHandle::spawn_storage(
reannounce, writer, options, networking,
))
}
}