diff --git a/src/feed.rs b/src/feed.rs index 8566644..71a25e5 100644 --- a/src/feed.rs +++ b/src/feed.rs @@ -3,94 +3,94 @@ use url::Url; /// Export crawl index to the RSS file pub struct Feed { - description: Option, - link: Option, - title: String, - trackers: Option>, + buffer: String, + canonical: Option, } impl Feed { - pub fn init( - title: String, - description: Option, - link: Option, - trackers: Option>, + pub fn new( + title: &str, + description: Option<&str>, + canonical: Option, + capacity: usize, ) -> Self { - Self { - description: description.map(escape), - link: link.map(|s| escape(s.to_string())), - title: escape(title), - trackers, - } - } - - pub fn transaction(&self, capacity: usize) -> String { let t = chrono::Utc::now().to_rfc2822(); - let mut b = String::with_capacity(capacity); + let mut buffer = String::with_capacity(capacity); - b.push_str(""); + buffer.push_str(""); - b.push_str(""); - b.push_str(&t); - b.push_str(""); + buffer.push_str(""); + buffer.push_str(&t); + buffer.push_str(""); - b.push_str(""); - b.push_str(&t); - b.push_str(""); + buffer.push_str(""); + buffer.push_str(&t); + buffer.push_str(""); - b.push_str(""); - b.push_str(&self.title); - b.push_str(""); + buffer.push_str(""); + buffer.push_str(title); + buffer.push_str(""); - if let Some(ref description) = self.description { - b.push_str(""); - b.push_str(description); - b.push_str("") + if let Some(d) = description { + buffer.push_str(""); + buffer.push_str(d); + buffer.push_str("") } - if let Some(ref link) = self.link { - b.push_str(""); - b.push_str(link); - b.push_str("") + if let Some(ref c) = canonical { + // @TODO required the RSS specification! + buffer.push_str(""); + buffer.push_str(c.as_str()); + buffer.push_str("") } - b + Self { buffer, canonical } } /// Append `item` to the feed `channel` - pub fn push(&self, buffer: &mut String, torrent: Torrent) { - buffer.push_str(&format!( + pub fn push(&mut self, torrent: Torrent) { + self.buffer.push_str(&format!( "{}{}{}", torrent.info_hash, escape( - torrent + &torrent .name .as_ref() .map(|b| b.to_string()) .unwrap_or("?".into()) // @TODO ), - escape(torrent.magnet(self.trackers.as_ref())) + self.canonical + .clone() + .map(|mut c| escape({ + c.set_path(&torrent.info_hash); + c.set_fragment(None); + c.set_query(None); + c.as_str() + })) + .unwrap_or(escape(&torrent.info_hash)) // should be non-optional absolute URL + // by the RSS specification @TODO )); - buffer.push_str(""); - buffer.push_str(&format!("{}\n{}", torrent.size(), torrent.files())); - buffer.push_str(""); + self.buffer.push_str(""); + self.buffer + .push_str(&format!("{}\n{}", torrent.size(), torrent.files())); + self.buffer.push_str(""); - buffer.push_str(""); - buffer.push_str(&torrent.time.to_rfc2822()); - buffer.push_str(""); + self.buffer.push_str(""); + self.buffer.push_str(&torrent.time.to_rfc2822()); + self.buffer.push_str(""); - buffer.push_str("") + self.buffer.push_str("") } /// Write final bytes - pub fn commit(&self, mut buffer: String) -> String { - buffer.push_str(""); - buffer + pub fn commit(mut self) -> String { + self.buffer.push_str(""); + self.buffer } } -fn escape(subject: String) -> String { - subject +fn escape(value: &str) -> String { + value .replace('&', "&") .replace('<', "<") .replace('>', ">") diff --git a/src/main.rs b/src/main.rs index 21f494c..137a3f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -141,8 +141,13 @@ fn info( } #[get("/rss")] -fn rss(feed: &State, public: &State) -> Result, Custom> { - let mut b = feed.transaction(1024); // @TODO +fn rss(meta: &State, public: &State) -> Result, Custom> { + let mut f = Feed::new( + &meta.title, + meta.description.as_deref(), + meta.canonical.clone(), + 1024, // @TODO + ); for t in public .torrents( Some((Sort::Modified, Order::Desc)), @@ -155,27 +160,18 @@ fn rss(feed: &State, public: &State) -> Result, Cus })? .1 { - feed.push( - &mut b, - Torrent::from_public(&t.bytes, t.time).map_err(|e| { - error!("Torrent parse error: `{e}`"); - Custom(Status::InternalServerError, E.to_string()) - })?, - ) + f.push(Torrent::from_public(&t.bytes, t.time).map_err(|e| { + error!("Torrent parse error: `{e}`"); + Custom(Status::InternalServerError, E.to_string()) + })?) } - Ok(RawXml(feed.commit(b))) + Ok(RawXml(f.commit())) } #[launch] fn rocket() -> _ { use clap::Parser; let config = Config::parse(); - let feed = Feed::init( - config.title.clone(), - config.description.clone(), - config.canonical_url.clone(), - config.tracker.clone(), - ); let scraper = Scraper::init( config .scrape @@ -215,7 +211,6 @@ fn rocket() -> _ { rocket::Config::default() } }) - .manage(feed) .manage(scraper) .manage(Public::init(config.public.clone(), config.list_limit, config.capacity).unwrap()) .manage(Meta {