From c08f0edcb8da6a78a8e9edcf3eaa14e633bf0e91 Mon Sep 17 00:00:00 2001 From: Lorenz Leitner Date: Mon, 11 Oct 2021 18:25:43 +0200 Subject: Rename wa, change anyhow version, make reqwest dependency more specific Due to MR comments Are you happy now audron? --- Cargo.lock | 236 ++++++++++++++------------------------------- Cargo.toml | 4 +- src/hooks/mod.rs | 2 +- src/hooks/wa.rs | 141 --------------------------- src/hooks/wolfram_alpha.rs | 141 +++++++++++++++++++++++++++ src/main.rs | 2 +- 6 files changed, 215 insertions(+), 311 deletions(-) delete mode 100644 src/hooks/wa.rs create mode 100644 src/hooks/wolfram_alpha.rs diff --git a/Cargo.lock b/Cargo.lock index 24907dd..22387f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "0.7.18" @@ -36,6 +42,19 @@ dependencies = [ "serde_json", ] +[[package]] +name = "async-compression" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443ccbb270374a2b1055fc72da40e1f237809cd6bb0e97e66d264cd138473a6" +dependencies = [ + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "atty" version = "0.2.14" @@ -170,28 +189,21 @@ dependencies = [ ] [[package]] -name = "core-foundation" -version = "0.9.1" +name = "cpufeatures" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +checksum = "dec1028182c380cc45a2e2c5ec841134f2dfd0f8f5f0a5bcd68004f81b5efdf4" dependencies = [ - "core-foundation-sys", "libc", ] [[package]] -name = "core-foundation-sys" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" - -[[package]] -name = "cpufeatures" -version = "0.1.1" +name = "crc32fast" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec1028182c380cc45a2e2c5ec841134f2dfd0f8f5f0a5bcd68004f81b5efdf4" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "libc", + "cfg-if", ] [[package]] @@ -293,25 +305,22 @@ dependencies = [ ] [[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" +name = "flate2" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ - "foreign-types-shared", + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", ] [[package]] -name = "foreign-types-shared" -version = "0.1.1" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" @@ -539,16 +548,18 @@ dependencies = [ ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-rustls" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" dependencies = [ - "bytes", + "futures-util", "hyper", - "native-tls", + "log", + "rustls", "tokio", - "tokio-native-tls", + "tokio-rustls", + "webpki", ] [[package]] @@ -608,7 +619,7 @@ dependencies = [ "tokio-rustls", "tokio-stream", "tokio-util", - "webpki-roots", + "webpki-roots 0.20.0", ] [[package]] @@ -696,6 +707,16 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + [[package]] name = "mio" version = "0.7.11" @@ -736,24 +757,6 @@ dependencies = [ "serde_urlencoded", ] -[[package]] -name = "native-tls" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "ntapi" version = "0.3.6" @@ -804,39 +807,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "openssl" -version = "0.10.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-sys", -] - -[[package]] -name = "openssl-probe" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" - -[[package]] -name = "openssl-sys" -version = "0.9.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "parking_lot" version = "0.11.1" @@ -909,12 +879,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb" - [[package]] name = "ppv-lite86" version = "0.2.10" @@ -1027,21 +991,13 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "reqwest" version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51c732d463dd300362ffb44b7b125f299c23d2990411a4253824630ebc7467fb" dependencies = [ + "async-compression", "base64", "bytes", "encoding_rs", @@ -1050,24 +1006,26 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-tls", + "hyper-rustls", "ipnet", "js-sys", "lazy_static", "log", "mime", - "native-tls", "percent-encoding", "pin-project-lite", + "rustls", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-native-tls", + "tokio-rustls", + "tokio-util", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 0.21.1", "winreg", ] @@ -1119,16 +1077,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "schannel" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" -dependencies = [ - "lazy_static", - "winapi", -] - [[package]] name = "scopeguard" version = "1.1.0" @@ -1145,29 +1093,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "security-framework" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "sedregex" version = "0.2.4" @@ -1308,20 +1233,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "tempfile" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" -dependencies = [ - "cfg-if", - "libc", - "rand", - "redox_syscall", - "remove_dir_all", - "winapi", -] - [[package]] name = "thiserror" version = "1.0.24" @@ -1407,16 +1318,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.22.0" @@ -1604,12 +1505,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.3" @@ -1727,6 +1622,15 @@ dependencies = [ "webpki", ] +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 1f31a40..da32799 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" toml = "0.5" -anyhow = "1.0.44" +anyhow = "1" futures = "0.3" tokio = { version = "1.5.0", features = ["full", "rt-multi-thread"] } @@ -30,7 +30,7 @@ sedregex = { version = "0.2", git = "https://gitlab.com/audron/sedregex" } rand = "0.8.3" -reqwest = "0.11" +reqwest = { version = "0.11", default-features = false, features = ["rustls-tls", "gzip"] } [dev-dependencies] mockito = "0.30.0" diff --git a/src/hooks/mod.rs b/src/hooks/mod.rs index 7f7a29c..cdf3787 100644 --- a/src/hooks/mod.rs +++ b/src/hooks/mod.rs @@ -7,7 +7,7 @@ pub mod intensify; pub mod pet; pub mod sed; pub mod shifty_eyes; -pub mod wa; +pub mod wolfram_alpha; pub use intensify::intensify; pub use shifty_eyes::shifty_eyes; diff --git a/src/hooks/wa.rs b/src/hooks/wa.rs deleted file mode 100644 index cb4bc4c..0000000 --- a/src/hooks/wa.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::util::web::shorten_url; -use anyhow::{bail, Context, Error, Result}; -use futures::try_join; -use irc::client::prelude::*; -use macros::privmsg; -use reqwest::{get, Url}; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug)] -struct WaResponse { - queryresult: QueryResult, -} - -#[derive(Serialize, Deserialize, Debug)] -struct QueryResult { - pods: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -struct Pod { - title: String, - id: String, - primary: Option, - subpods: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -struct SubPod { - plaintext: String, -} - -/// Reduces all 'pod' plaintexts to a single string. -/// Same as gonzobot does it. -fn to_single_string(wa_res: WaResponse) -> String { - wa_res - .queryresult - .pods - .iter() - .filter(|it| it.id.to_lowercase() != "input" && it.primary.is_some()) - .map(|pod| { - let subpod_texts = pod - .subpods - .iter() - .map(|subpod| subpod.plaintext.clone()) - .collect::>() - .join(", "); - - format!("{}: {}", &pod.title, subpod_texts) - }) - .collect::>() - .join(" - ") -} - -fn get_url(query_str: &str, api_key: Option<&str>, base_url: Option<&str>) -> String { - let wa_url = "http://api.wolframalpha.com"; - let api_url = format!( - "{}/v2/query?input={}&appid={}&output=json", - base_url.unwrap_or(wa_url), - query_str, - api_key.unwrap_or("XXX"), // Allow tests to run without a key - ); - api_url -} - -async fn send_wa_req(url: &str) -> Result { - let body = get(Url::parse(url).context("Failed to parse url")?) - .await - .context("Failed to make request")? - .text() - .await - .context("failed to get request response text")?; - Ok(body) -} - -async fn handle_wa_req(url: &str) -> Result { - let res_body = send_wa_req(url).await?; - let parsed = serde_json::from_str(&res_body)?; - Ok(parsed) -} - -/// Sends a request to the Wolfram Alpha API, returns a plain text response. -#[tracing::instrument] -async fn wa_query( - query_str: &str, - api_key: Option<&str>, - base_url: Option<&str>, -) -> Result { - let user_url = format!("http://www.wolframalpha.com/input/?i={}", query_str); - let user_url_shortened_fut = shorten_url(&user_url); - - let url = get_url(query_str, api_key, base_url); - let wa_res_fut = handle_wa_req(&url); - - // Can't just (foo.await, bar.await), smh - // https://rust-lang.github.io/async-book/06_multiple_futures/02_join.html - let (wa_res, user_url_shortened) = try_join!(wa_res_fut, user_url_shortened_fut)?; - - Ok(format!( - "{} - {}", - &user_url_shortened, - to_single_string(wa_res) - )) -} - -pub async fn wa(bot: &crate::Bot, msg: Message) -> Result<()> { - privmsg!(msg, { - let input = text.chars().as_str().splitn(2, " ").collect::>(); - if input.len() != 2 { - bail!("Empty input for WA query"); - } - let content = input[1].trim(); - bot.send_privmsg( - msg.response_target() - .context("failed to get response target")?, - &wa_query(content, Some(&bot.config.settings.wa_api_key), None).await?, - )?; - }) -} - -#[cfg(test)] -mod tests { - - use super::wa_query; - use anyhow::{Error, Result}; - use mockito::{self, Matcher}; - - #[tokio::test] - async fn test_query_result_json_parsing() -> Result<(), Error> { - let body = include_str!("../../tests/resources/wolfram_alpha_api_response.json"); - let _m = mockito::mock("GET", Matcher::Any) - // Trimmed down version of a full WA response: - .with_body(body) - .create(); - mockito::start(); - - let res = wa_query("5/10", None, Some(&mockito::server_url())).await?; - let res_without_link = res.splitn(2, "-").collect::>()[1].trim(); - assert_eq!(res_without_link, "Exact result: 1/2 - Decimal form: 0.5"); - Ok(()) - } -} diff --git a/src/hooks/wolfram_alpha.rs b/src/hooks/wolfram_alpha.rs new file mode 100644 index 0000000..cb4bc4c --- /dev/null +++ b/src/hooks/wolfram_alpha.rs @@ -0,0 +1,141 @@ +use crate::util::web::shorten_url; +use anyhow::{bail, Context, Error, Result}; +use futures::try_join; +use irc::client::prelude::*; +use macros::privmsg; +use reqwest::{get, Url}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct WaResponse { + queryresult: QueryResult, +} + +#[derive(Serialize, Deserialize, Debug)] +struct QueryResult { + pods: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +struct Pod { + title: String, + id: String, + primary: Option, + subpods: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +struct SubPod { + plaintext: String, +} + +/// Reduces all 'pod' plaintexts to a single string. +/// Same as gonzobot does it. +fn to_single_string(wa_res: WaResponse) -> String { + wa_res + .queryresult + .pods + .iter() + .filter(|it| it.id.to_lowercase() != "input" && it.primary.is_some()) + .map(|pod| { + let subpod_texts = pod + .subpods + .iter() + .map(|subpod| subpod.plaintext.clone()) + .collect::>() + .join(", "); + + format!("{}: {}", &pod.title, subpod_texts) + }) + .collect::>() + .join(" - ") +} + +fn get_url(query_str: &str, api_key: Option<&str>, base_url: Option<&str>) -> String { + let wa_url = "http://api.wolframalpha.com"; + let api_url = format!( + "{}/v2/query?input={}&appid={}&output=json", + base_url.unwrap_or(wa_url), + query_str, + api_key.unwrap_or("XXX"), // Allow tests to run without a key + ); + api_url +} + +async fn send_wa_req(url: &str) -> Result { + let body = get(Url::parse(url).context("Failed to parse url")?) + .await + .context("Failed to make request")? + .text() + .await + .context("failed to get request response text")?; + Ok(body) +} + +async fn handle_wa_req(url: &str) -> Result { + let res_body = send_wa_req(url).await?; + let parsed = serde_json::from_str(&res_body)?; + Ok(parsed) +} + +/// Sends a request to the Wolfram Alpha API, returns a plain text response. +#[tracing::instrument] +async fn wa_query( + query_str: &str, + api_key: Option<&str>, + base_url: Option<&str>, +) -> Result { + let user_url = format!("http://www.wolframalpha.com/input/?i={}", query_str); + let user_url_shortened_fut = shorten_url(&user_url); + + let url = get_url(query_str, api_key, base_url); + let wa_res_fut = handle_wa_req(&url); + + // Can't just (foo.await, bar.await), smh + // https://rust-lang.github.io/async-book/06_multiple_futures/02_join.html + let (wa_res, user_url_shortened) = try_join!(wa_res_fut, user_url_shortened_fut)?; + + Ok(format!( + "{} - {}", + &user_url_shortened, + to_single_string(wa_res) + )) +} + +pub async fn wa(bot: &crate::Bot, msg: Message) -> Result<()> { + privmsg!(msg, { + let input = text.chars().as_str().splitn(2, " ").collect::>(); + if input.len() != 2 { + bail!("Empty input for WA query"); + } + let content = input[1].trim(); + bot.send_privmsg( + msg.response_target() + .context("failed to get response target")?, + &wa_query(content, Some(&bot.config.settings.wa_api_key), None).await?, + )?; + }) +} + +#[cfg(test)] +mod tests { + + use super::wa_query; + use anyhow::{Error, Result}; + use mockito::{self, Matcher}; + + #[tokio::test] + async fn test_query_result_json_parsing() -> Result<(), Error> { + let body = include_str!("../../tests/resources/wolfram_alpha_api_response.json"); + let _m = mockito::mock("GET", Matcher::Any) + // Trimmed down version of a full WA response: + .with_body(body) + .create(); + mockito::start(); + + let res = wa_query("5/10", None, Some(&mockito::server_url())).await?; + let res_without_link = res.splitn(2, "-").collect::>()[1].trim(); + assert_eq!(res_without_link, "Exact result: 1/2 - Decimal form: 0.5"); + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index f337613..fd2d3b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,7 +55,7 @@ async fn main() { async command( "wa", "Returns Wolfram Alpha results for a query", - catinator::hooks::wa::wa + catinator::hooks::wolfram_alpha::wa ), ]; } -- cgit v1.2.3