use std::ffi;
use std::io;
use std::path::PathBuf;
use transmission_sys;
use crate::error::{Error, TrResult};
#[derive(Default)]
pub struct TorrentBuilder {
comment: Option<String>,
trackers: Vec<String>,
file: PathBuf,
output_file: Option<PathBuf>,
webseeds: Option<Vec<String>>,
is_private: bool,
}
impl TorrentBuilder {
pub fn new() -> Self {
Self {
comment: None,
trackers: Vec::new(),
file: PathBuf::new(),
output_file: None,
webseeds: None,
is_private: false,
}
}
#[allow(clippy::while_immutable_condition)]
pub fn build(self) -> TrResult<String> {
let file_c_string = ffi::CString::new(self.file.to_str().unwrap()).unwrap();
let mut tr_trackers: Vec<transmission_sys::tr_tracker_info> = Vec::new();
let meta_builder;
let tr_comment = if let Some(cmt) = self.comment {
ffi::CString::new(cmt).unwrap()
} else {
ffi::CString::new("").unwrap()
};
for (i, tracker) in self.trackers.iter().enumerate() {
let tracker_announce = ffi::CString::new(format!("{}/announce", tracker)).unwrap();
let tracker_scrape = ffi::CString::new(format!("{}/scrape", tracker)).unwrap();
tr_trackers.push(transmission_sys::tr_tracker_info {
tier: i as i32,
announce: tracker_announce.into_raw(),
scrape: tracker_scrape.into_raw(),
id: i as u32,
});
}
let output_path = if let Some(ofile) = self.output_file {
ffi::CString::new(format!("{}.torrent", ofile.display())).unwrap()
} else {
ffi::CString::new(format!("{}.torrent", self.file.display())).unwrap()
};
let error: Error;
unsafe {
meta_builder = transmission_sys::tr_metaInfoBuilderCreate(file_c_string.as_ptr());
transmission_sys::tr_makeMetaInfo(
meta_builder,
output_path.as_ptr(), tr_trackers.as_ptr(),
tr_trackers.len() as i32,
tr_comment.as_ptr(),
self.is_private,
);
while !(*meta_builder).isDone {}
error = Error::from((*meta_builder).result);
transmission_sys::tr_metaInfoBuilderFree(meta_builder);
}
error
.to_result()
.and_then(|_| Ok(output_path.to_str().unwrap().to_owned()))
}
pub fn set_file(mut self, file: &str) -> io::Result<Self> {
self.file = PathBuf::from(file).canonicalize()?;
Ok(self)
}
pub fn set_output_file(mut self, file: &str) -> Self {
self.output_file = Some(PathBuf::from(file));
self
}
pub fn add_tracker(mut self, tracker: &str) -> Self {
self.trackers.push(tracker.to_owned());
self
}
pub fn set_trackers(mut self, trackers: Vec<&str>) -> Self {
self.trackers = trackers.iter().map(|s| String::from(*s)).collect();
self
}
pub fn set_comment(mut self, comment: &str) -> Self {
self.comment = Some(comment.to_owned());
self
}
pub fn add_webseed(mut self, webseed: &str) -> Self {
if self.webseeds.is_some() {
let mut wbs = self.webseeds.unwrap().clone();
wbs.push(webseed.to_owned());
self.webseeds = Some(wbs);
} else {
self.webseeds = Some(vec![webseed.to_owned()]);
}
self
}
pub fn set_webseeds(mut self, webseeds: Vec<&str>) -> Self {
if webseeds.is_empty() {
self.webseeds = Some(webseeds.iter().map(|s| String::from(*s)).collect());
} else {
self.webseeds = None;
}
self
}
}