diff --git a/src/bot.rs b/src/bot.rs index a1e33e2..7f00b12 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -4,29 +4,31 @@ use fancy_regex::{Captures, Regex}; use std::collections::HashMap; use tokio::sync::{Mutex, RwLock}; -fn separate_to_space(str: &str, prefix_len: usize) -> (&str, Option<&str>) { +fn dissect<'a>(prefix: &str, str: &'a str) -> Option<(&'a str, Option<&'a str>)> { + let str = str.strip_prefix(prefix)?; if let Some(o) = str.find(' ') { - (&str[prefix_len..o], Some(&str[o + 1..])) + Some((&str[..o], Some(&str[o + 1..]))) } else { - (&str[prefix_len..], None) + Some((str, None)) } } #[async_trait] pub trait Trigger { - async fn execute<'a>(&mut self, msg: Message<'a>, captures: Captures<'a>) -> anyhow::Result; + async fn execute<'a>(&mut self, msg: Context<'a>, captures: Captures<'a>) -> anyhow::Result; } #[async_trait] pub trait Command { - async fn execute(&mut self, msg: Message<'_>) -> anyhow::Result; + async fn execute(&mut self, msg: Context<'_>) -> anyhow::Result; } -pub struct Message<'a> { +pub struct Context<'a> { pub last_msg: &'a RwLock>, pub author: &'a str, // in case of triggers, this is always Some(...) pub content: Option<&'a str>, + pub db: &'a ExecutorConnection } pub struct Bot anyhow::Result<()>> { @@ -64,13 +66,13 @@ impl anyhow::Result<()>> Bot { author: &str, content: &str, ) -> anyhow::Result<()> { - if content.starts_with(&self.prefix) { - let (command, remainder) = separate_to_space(content, self.prefix.len()); + if let Some((command, remainder)) = dissect(&self.prefix, content) { if let Some(handler) = self.commands.get(command) { - let msg = Message { + let msg = Context { last_msg: &self.last_msg, author, - content: remainder + content: remainder, + db: &self.db }; return (self.sendmsg)(origin.into(), handler.lock().await.execute(msg).await?) } @@ -79,10 +81,11 @@ impl anyhow::Result<()>> Bot { for trigger in &self.triggers { let captures = trigger.0.captures(content)?; if let Some(captures) = captures { - let msg = Message { + let msg = Context { last_msg: &self.last_msg, author, - content: Some(content) + content: Some(content), + db: &self.db }; return (self.sendmsg)(origin.into(), trigger.1.lock().await.execute(msg, captures).await?) } diff --git a/src/commands/debug.rs b/src/commands/debug.rs index ccfbed2..9f24347 100644 --- a/src/commands/debug.rs +++ b/src/commands/debug.rs @@ -1,12 +1,12 @@ use async_trait::async_trait; -use crate::bot::{Command, Message}; +use crate::bot::{Command, Context}; pub struct LastMsg; #[async_trait] impl Command for LastMsg { //noinspection RsNeedlessLifetimes - async fn execute<'a>(&mut self, msg: Message<'a>) -> anyhow::Result { + async fn execute<'a>(&mut self, msg: Context<'a>) -> anyhow::Result { let nick = msg.content.unwrap_or(msg.author); let lastmsg = msg.last_msg.read().await; Ok(format!("{}: {:?}", nick, lastmsg.get(nick))) diff --git a/src/commands/eval.rs b/src/commands/eval.rs index 00a9626..714bbc7 100644 --- a/src/commands/eval.rs +++ b/src/commands/eval.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use async_trait::async_trait; -use meval::Context; -use crate::bot::{Command, Message}; +use crate::bot::{Command, Context}; #[derive(Default)] pub struct Eval { @@ -10,10 +9,10 @@ pub struct Eval { #[async_trait] impl Command for Eval { - async fn execute(&mut self, msg: Message<'_>) -> anyhow::Result { + async fn execute(&mut self, msg: Context<'_>) -> anyhow::Result { if let Some(expr) = msg.content { let last_eval = self.last_eval.entry(msg.author.into()).or_insert(0.0); - let mut meval_ctx = Context::new(); + let mut meval_ctx = meval::Context::new(); let value = meval::eval_str_with_context(expr, meval_ctx.var("x", *last_eval))?; *last_eval = value; Ok(format!("{} = {}", expr, value)) diff --git a/src/commands/help.rs b/src/commands/help.rs index eb68797..e8142af 100644 --- a/src/commands/help.rs +++ b/src/commands/help.rs @@ -1,4 +1,4 @@ -use crate::bot::{Message, Command}; +use crate::bot::{Context, Command}; use async_trait::async_trait; const HELP: &str = concat!( @@ -13,7 +13,7 @@ pub struct Help; #[async_trait] impl Command for Help { - async fn execute(&mut self, _msg: Message<'_>) -> anyhow::Result { + async fn execute(&mut self, _msg: Context<'_>) -> anyhow::Result { Ok(HELP.into()) } } diff --git a/src/commands/leek.rs b/src/commands/leek.rs index 0c2303e..ba4529d 100644 --- a/src/commands/leek.rs +++ b/src/commands/leek.rs @@ -1,4 +1,4 @@ -use crate::bot::{Command, Message}; +use crate::bot::{Command, Context}; use arrayvec::ArrayString; use async_trait::async_trait; use rand::Rng; @@ -111,7 +111,7 @@ enum LeekCommand { Mock, } -async fn execute_leek(cmd: LeekCommand, msg: &Message<'_>) -> anyhow::Result { +async fn execute_leek(cmd: LeekCommand, msg: &Context<'_>) -> anyhow::Result { let nick = msg.content.unwrap_or(msg.author); match msg.last_msg.read().await.get(nick) { Some(msg) => Ok(match cmd { @@ -130,21 +130,21 @@ pub struct Mock; #[async_trait] impl Command for Owo { - async fn execute(&mut self, msg: Message<'_>) -> anyhow::Result { + async fn execute(&mut self, msg: Context<'_>) -> anyhow::Result { execute_leek(LeekCommand::Owo, &msg).await } } #[async_trait] impl Command for Leet { - async fn execute(&mut self, msg: Message<'_>) -> anyhow::Result { + async fn execute(&mut self, msg: Context<'_>) -> anyhow::Result { execute_leek(LeekCommand::Leet, &msg).await } } #[async_trait] impl Command for Mock { - async fn execute(&mut self, msg: Message<'_>) -> anyhow::Result { + async fn execute(&mut self, msg: Context<'_>) -> anyhow::Result { execute_leek(LeekCommand::Mock, &msg).await } } diff --git a/src/commands/sed.rs b/src/commands/sed.rs index d5e60ee..2f7be13 100644 --- a/src/commands/sed.rs +++ b/src/commands/sed.rs @@ -1,12 +1,12 @@ use async_trait::async_trait; use fancy_regex::Captures; -use crate::bot::{Message, Trigger}; +use crate::bot::{Context, Trigger}; pub struct Sed; #[async_trait] impl Trigger for Sed { - async fn execute<'a>(&mut self, msg: Message<'a>, captures: Captures<'a>) -> anyhow::Result { + async fn execute<'a>(&mut self, msg: Context<'a>, captures: Captures<'a>) -> anyhow::Result { let foreign_author; let author = if let Some(author) = captures.name("u").map(|m| m.as_str()) { foreign_author = true; diff --git a/src/commands/spotify.rs b/src/commands/spotify.rs index 967d311..83e3ed5 100644 --- a/src/commands/spotify.rs +++ b/src/commands/spotify.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use fancy_regex::Captures; use rspotify::clients::BaseClient; use rspotify::model::{Id, PlayableItem}; -use crate::bot::{Message, Trigger}; +use crate::bot::{Context, Trigger}; pub struct Spotify { spotify: ClientCredsSpotify, @@ -21,7 +21,7 @@ impl Spotify { #[async_trait] impl Trigger for Spotify { - async fn execute<'a>(&mut self, msg: Message<'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( diff --git a/src/commands/title.rs b/src/commands/title.rs index 8ae14ee..c636f36 100644 --- a/src/commands/title.rs +++ b/src/commands/title.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use fancy_regex::{Captures, Regex}; use reqwest::Client; use htmlescape::decode_html; -use crate::bot::{Message, Trigger}; +use crate::bot::{Context, Trigger}; pub struct Title { http: Client, @@ -20,7 +20,7 @@ impl Title { #[async_trait] impl Trigger for Title { - async fn execute<'a>(&mut self, _msg: Message<'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); diff --git a/src/commands/waifu.rs b/src/commands/waifu.rs index 95a6ac0..0eec050 100644 --- a/src/commands/waifu.rs +++ b/src/commands/waifu.rs @@ -1,4 +1,4 @@ -use crate::bot::{Message, Command}; +use crate::bot::{Context, Command}; use async_trait::async_trait; use reqwest::Client; use serde_json::Value; @@ -10,7 +10,7 @@ pub struct Waifu { #[async_trait] impl Command for Waifu { - async fn execute(&mut self, msg: Message<'_>) -> anyhow::Result { + 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) diff --git a/src/main.rs b/src/main.rs index b92e5e4..0c640fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,12 +51,6 @@ async fn terminate_signal() { let _ = ctrlc.recv().await; } -pub struct AppState anyhow::Result<()>> { - client: Arc, - stream: ClientStream, - bot: Bot, -} - #[tokio::main] async fn main() -> anyhow::Result<()> { tracing_subscriber::fmt() @@ -119,13 +113,8 @@ async fn main() -> anyhow::Result<()> { bot.add_command("lastmsg".into(), LastMsg); } - let state = AppState { - client: client.clone(), - stream, - bot, - }; let message_loop_task = tokio::spawn(async move { - if let Err(e) = message_loop(state).await { + if let Err(e) = message_loop(stream, bot).await { let _err = etx.send(e); } }); @@ -160,16 +149,17 @@ async fn main() -> anyhow::Result<()> { } async fn message_loop anyhow::Result<()>>( - mut state: AppState, + mut stream: ClientStream, + bot: Bot ) -> anyhow::Result<()> { - while let Some(message) = state.stream.next().await.transpose()? { + while let Some(message) = stream.next().await.transpose()? { if let Command::PRIVMSG(ref origin, content) = message.command { if origin.is_channel_name() { if let Some(author) = message.prefix.as_ref().and_then(|p| match p { Prefix::Nickname(name, _, _) => Some(&name[..]), _ => None, }) { - state.bot.handle_message(origin, author, &content).await + bot.handle_message(origin, author, &content).await } else { tracing::warn!("Couldn't get the author for a message"); }