diff --git a/pkgs/mx-sanebot/Cargo.lock b/pkgs/mx-sanebot/Cargo.lock index 9c91ba29..9eaeea3c 100644 --- a/pkgs/mx-sanebot/Cargo.lock +++ b/pkgs/mx-sanebot/Cargo.lock @@ -1360,6 +1360,8 @@ dependencies = [ "matrix-sdk", "ruma", "ruma-client-api", + "serde", + "serde_json", "tokio", ] diff --git a/pkgs/mx-sanebot/Cargo.toml b/pkgs/mx-sanebot/Cargo.toml index 2dca7013..dbb135bb 100644 --- a/pkgs/mx-sanebot/Cargo.toml +++ b/pkgs/mx-sanebot/Cargo.toml @@ -8,7 +8,9 @@ edition = "2021" [dependencies] anyhow = "1.0" futures = "0.3" -matrix-sdk = "0.6.2" +matrix-sdk = "0.6.2" # TODO: bump ruma = "*" # matrix-sdk dep ruma-client-api = "*" # ruma dep +serde = "*" +serde_json = "*" tokio = { version = "1.20.1", features = ["macros", "rt-multi-thread"] } diff --git a/pkgs/mx-sanebot/src/msg_handler.rs b/pkgs/mx-sanebot/src/msg_handler.rs index c8c36931..8ac83610 100644 --- a/pkgs/mx-sanebot/src/msg_handler.rs +++ b/pkgs/mx-sanebot/src/msg_handler.rs @@ -3,6 +3,9 @@ use std::fmt; use std::process; use std::str; +use serde_json; +use serde::Deserialize; + use super::parsing::{self, Parser}; @@ -200,24 +203,36 @@ impl Request { fn evaluate(self) -> Response { match self { Request::Help => Response::Help, - Request::Bt => Response::Bt( - exec_stdout("sane-bt-show", &[]) - .unwrap_or_else(|| - "failed to retrieve torrent status".to_owned()) - ), - Request::BtSearch(phrase) => Response::BtSearch( - exec_stdout("sane-bt-search", &[&*phrase]) - .unwrap_or_else(|| - "failed to complete torrent search".to_owned()) - ), + Request::Bt => match exec_stdout("sane-bt-show", &[]) { + Some(m) => Response::Bt(m), + None => Response::Error("failed to execute sane-bt-show".to_owned()), + }, + Request::BtSearch(phrase) => match exec_stdout("sane-bt-search", &[&*phrase, "--json"]) { + Some(r) => match serde_json::from_str(&r) { + Ok(torrents) => Response::BtSearch(torrents), + Err(e) => Response::Error(format!("failed to decode sane-bt-search response: {e}\nresponse: {r}")), + }, + None => Response::Error("failed to execute sane-bt-search".to_owned()), + }, } } } +#[derive(Deserialize)] +pub struct Torrent { + seeders: u32, + pub_date: String, // YYYY-MM-DD + size: u64, + tracker: String, + title: String, + magnet: String, +} + pub enum Response { + Error(String), Help, Bt(String), - BtSearch(String), + BtSearch(Vec), } impl Response { @@ -233,7 +248,42 @@ impl Response { "#.to_owned() ), - // not yet implemented + Response::BtSearch(torrents) => Some({ + let fmt_torrents = torrents.into_iter().map(|t| { + let Torrent { + seeders, + pub_date, + size, + tracker, + title, + magnet, + } = t; + let mib = size >> 20; + format!(r#" + + {seeders} + {pub_date} + {mib} + {tracker} + {title} + {magnet} + + "#) + }).collect::(); + format!(r#" + + + + + + + + + + {fmt_torrents} +
SeedersDateSize (MiB)TrackerTitleURL
+ "#) + }), _ => None, } } @@ -242,6 +292,7 @@ impl Response { impl fmt::Display for Response { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { + Response::Error(e) => write!(f, "{}", e)?, Response::Help => { write!(f, "commands:\n")?; write!(f, " !help => show this message\n")?; @@ -249,7 +300,7 @@ impl fmt::Display for Response { write!(f, " !bt search => search for torrents\n")?; }, Response::Bt(stdout) => write!(f, "{}", stdout)?, - Response::BtSearch(stdout) => write!(f, "{}", stdout)?, + Response::BtSearch(torrents) => write!(f, "{} torrents", torrents.len())?, } Ok(()) }