diff --git a/src/commands/debug.rs b/src/commands/debug.rs index 9f24347..6525b24 100644 --- a/src/commands/debug.rs +++ b/src/commands/debug.rs @@ -1,14 +1,13 @@ -use async_trait::async_trait; use crate::bot::{Command, Context}; +use async_trait::async_trait; pub struct LastMsg; #[async_trait] impl Command for LastMsg { - //noinspection RsNeedlessLifetimes - async fn execute<'a>(&mut self, msg: Context<'a>) -> anyhow::Result { + async fn execute(&mut self, msg: Context<'_>) -> anyhow::Result { let nick = msg.content.unwrap_or(msg.author); - let lastmsg = msg.last_msg.read().await; + let lastmsg = msg.history.read().await; Ok(format!("{}: {:?}", nick, lastmsg.get(nick))) } -} \ No newline at end of file +} diff --git a/src/commands/spotify.rs b/src/commands/spotify.rs index 83e3ed5..0b7a2f7 100644 --- a/src/commands/spotify.rs +++ b/src/commands/spotify.rs @@ -1,9 +1,9 @@ -use rspotify::{ClientCredsSpotify, Credentials}; +use crate::bot::{Context, Trigger}; use async_trait::async_trait; use fancy_regex::Captures; use rspotify::clients::BaseClient; use rspotify::model::{Id, PlayableItem}; -use crate::bot::{Context, Trigger}; +use rspotify::{ClientCredsSpotify, Credentials}; pub struct Spotify { spotify: ClientCredsSpotify, @@ -13,22 +13,25 @@ impl Spotify { pub async fn new(creds: Credentials) -> anyhow::Result { let mut spotify = ClientCredsSpotify::new(creds); spotify.request_token().await?; - Ok(Self { - spotify - }) + Ok(Self { spotify }) } } #[async_trait] impl Trigger for Spotify { - async fn execute<'a>(&mut self, msg: Context<'a>, captures: Captures<'a>) -> anyhow::Result { + async fn execute<'a>( + &mut self, + msg: Context<'a>, + captures: Captures<'a>, + ) -> anyhow::Result { let tp_group = captures.get(1).unwrap(); let id_group = captures.get(2).unwrap(); resolve_spotify( &mut self.spotify, &msg.content.unwrap()[tp_group.start()..tp_group.end()], &msg.content.unwrap()[id_group.start()..id_group.end()], - ).await + ) + .await } } diff --git a/src/commands/title.rs b/src/commands/title.rs index c636f36..ec2e893 100644 --- a/src/commands/title.rs +++ b/src/commands/title.rs @@ -1,26 +1,30 @@ +use crate::bot::{Context, Trigger}; use async_trait::async_trait; use fancy_regex::{Captures, Regex}; -use reqwest::Client; use htmlescape::decode_html; -use crate::bot::{Context, Trigger}; +use reqwest::Client; pub struct Title { http: Client, - title_regex: Regex + title_regex: Regex, } impl Title { pub fn new() -> anyhow::Result { Ok(Title { http: Client::new(), - title_regex: Regex::new(r"(?<=)(.*)(?=)")? + title_regex: Regex::new(r"(?<=)(.*)(?=)")?, }) } } #[async_trait] impl Trigger for Title { - async fn execute<'a>(&mut self, _msg: Context<'a>, captures: Captures<'a>) -> anyhow::Result { + async fn execute<'a>( + &mut self, + _msg: Context<'a>, + captures: Captures<'a>, + ) -> anyhow::Result { let url = captures.get(0).unwrap().as_str(); tracing::debug!("url: {}", url); @@ -33,18 +37,19 @@ impl Trigger for Title { let body = response.text().await?; if let Some(tm) = self.title_regex.find(&body)? { let title_match = &body[tm.start()..tm.end()]; - let result = decode_html(title_match).unwrap_or_else(|_| title_match.to_string()); + let result = + decode_html(title_match).unwrap_or_else(|_| title_match.to_string()); Ok(format!("\x039[Title]\x0311 {}", result)) } else { Ok("\x039[Title]\x0311 No title".into()) } } else { - let content_length = response.content_length().map(|l| (l/1024).to_string()); + let content_length = response.content_length().map(|l| (l / 1024).to_string()); let size = content_length.as_deref().unwrap_or("unknown"); Ok(format!("\x039[Title]\x0311 File: {}; {}kb", mime, size)) } } else { Ok("\x039[Title]\x0311 No Content-Type header".into()) - } + }; } -} \ No newline at end of file +} diff --git a/src/commands/waifu.rs b/src/commands/waifu.rs index 0eec050..235daae 100644 --- a/src/commands/waifu.rs +++ b/src/commands/waifu.rs @@ -1,22 +1,22 @@ -use crate::bot::{Context, Command}; +use crate::bot::{Command, Context}; use async_trait::async_trait; use reqwest::Client; use serde_json::Value; #[derive(Default)] pub struct Waifu { - http: Client + http: Client, } #[async_trait] impl Command for Waifu { async fn execute(&mut self, msg: Context<'_>) -> anyhow::Result { let category = msg.content.unwrap_or("waifu"); - let request = self.http.get(format!("https://api.waifu.pics/sfw/{}", category)).build()?; - let response = self.http.execute(request) - .await? - .text() - .await?; + let request = self + .http + .get(format!("https://api.waifu.pics/sfw/{}", category)) + .build()?; + let response = self.http.execute(request).await?.text().await?; let response = response.trim(); let value: Value = serde_json::from_str(response)?; let url = value["url"] diff --git a/src/database.rs b/src/database.rs index 91aea83..61cf51d 100644 --- a/src/database.rs +++ b/src/database.rs @@ -7,10 +7,12 @@ use tokio::sync::{ #[derive(Debug)] enum Task { - AddQuote(oneshot::Sender, Quote), - GetQuote(oneshot::Sender>, Option), - SearchQuotes(oneshot::Sender>>, String), - RandomNQuotes(oneshot::Sender>>, u8), + AddQuote(oneshot::Sender>, Quote), + GetQuote( + oneshot::Sender>>, + Option, + ), + SearchQuotes(oneshot::Sender>>, String), } pub struct DbExecutor { @@ -40,45 +42,34 @@ impl DbExecutor { while let Some(task) = self.rx.blocking_recv() { match task { Task::AddQuote(tx, quote) => { - if let Err(e) = self.db.execute( - "insert into quotes(quote,username) values(?,?)", - params![quote.quote, quote.author], - ) { - tracing::error!("A database error has occurred: {}", e); - tx.send(false).unwrap(); - } else { - tx.send(true).unwrap(); - } + let result = self + .db + .execute( + "insert into quotes(quote,username) values(?,?)", + params![quote.quote, quote.author], + ) + .map(|_| ()); + tx.send(result).unwrap(); } Task::GetQuote(tx, author) => { - let quote = if let Some(ref author) = author { + let result = if let Some(ref author) = author { self.db.query_row("select quote,username from quotes where username=? order by random() limit 1", params![author], |v| Ok(Quote {quote:v.get(0)?, author:v.get(1)?})) } else { self.db.query_row("select quote,username from quotes order by random() limit 1", params![], |v| Ok(Quote {quote:v.get(0)?, author:v.get(1)?})) - }.optional().unwrap_or_else(|e| { - tracing::error!("A database error has occurred: {}", e); - None - }); - tx.send(quote).unwrap(); + }.optional(); + tx.send(result).unwrap(); } Task::SearchQuotes(tx, query) => { tx.send(self.yield_quotes("select quote,username from quotes where quote like '%'||?1||'%' order by quote asc limit 5", params![query])).unwrap(); } - Task::RandomNQuotes(tx, count) => { - tx.send(self.yield_quotes( - "select quote,username from quotes order by random() limit ?", - params![count], - )) - .unwrap(); - } } } } - fn yield_quotes(&self, sql: &str, params: P) -> Option> { - match self.db.prepare(sql).and_then(|mut v| { + fn yield_quotes(&self, sql: &str, params: P) -> rusqlite::Result> { + self.db.prepare(sql).and_then(|mut v| { v.query(params).and_then(|mut v| { - let mut quotes: Vec = Vec::with_capacity(50); + let mut quotes: Vec = Vec::new(); while let Some(row) = v.next()? { quotes.push(Quote { quote: row.get(0)?, @@ -87,13 +78,7 @@ impl DbExecutor { } Ok(quotes) }) - }) { - Ok(o) => Some(o), - Err(e) => { - tracing::error!("A database error has occurred: {}", e); - None - } - } + }) } } @@ -128,23 +113,22 @@ macro_rules! executor_wrapper { impl ExecutorConnection { // WARNING: these methods are NOT cancel-safe - executor_wrapper!(add_quote, Task::AddQuote, bool, quote: Quote); + executor_wrapper!( + add_quote, + Task::AddQuote, + rusqlite::Result<()>, + quote: Quote + ); executor_wrapper!( get_quote, Task::GetQuote, - Option, + rusqlite::Result>, author: Option ); executor_wrapper!( search_quotes, Task::SearchQuotes, - Option>, + rusqlite::Result>, query: String ); - executor_wrapper!( - random_n_quotes, - Task::RandomNQuotes, - Option>, - count: u8 - ); }