aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJokler <jokler.contact@gmail.com>2019-12-16 07:13:13 +0100
committerJokler <jokler.contact@gmail.com>2019-12-16 07:13:13 +0100
commit46b36045d701d5727f4000790780025e38f94f8a (patch)
tree01332c77e57a71e0311ad7025d2c1c91605fe634
parentb1648f896702b6d45fa1099eaf26ac51c5dc053f (diff)
downloadfrippy-46b36045d701d5727f4000790780025e38f94f8a.tar.gz
frippy-46b36045d701d5727f4000790780025e38f94f8a.zip
Quote: Split methods and add a 'next' command
The 'next' command runs the previous get/search commands again but for the next index/offset.
-rw-r--r--src/plugins/quote/mod.rs238
1 files changed, 177 insertions, 61 deletions
diff --git a/src/plugins/quote/mod.rs b/src/plugins/quote/mod.rs
index e5117eb..893b3e6 100644
--- a/src/plugins/quote/mod.rs
+++ b/src/plugins/quote/mod.rs
@@ -1,9 +1,10 @@
+use std::collections::HashMap;
use std::fmt;
use std::marker::PhantomData;
use std::ops::Deref;
use std::str::FromStr;
-use antidote::RwLock;
+use antidote::{Mutex, RwLock};
use chrono::NaiveDateTime;
use irc::client::prelude::*;
use rand::{thread_rng, Rng};
@@ -26,9 +27,18 @@ enum QuoteResponse {
Private(String),
}
+#[derive(Clone)]
+enum PreviousCommand {
+ Get,
+ GetUser(String, Option<i32>),
+ Search(String, i32),
+ SearchUser(String, String, i32),
+}
+
#[derive(PluginName)]
pub struct Quote<T: Database, C: Client> {
quotes: RwLock<T>,
+ previous_map: Mutex<HashMap<String, PreviousCommand>>,
phantom: PhantomData<C>,
}
@@ -36,6 +46,7 @@ impl<T: Database, C: Client> Quote<T, C> {
pub fn new(db: T) -> Self {
Quote {
quotes: RwLock::new(db),
+ previous_map: Mutex::new(HashMap::new()),
phantom: PhantomData,
}
}
@@ -59,11 +70,13 @@ impl<T: Database, C: Client> Quote<T, C> {
created: NaiveDateTime::from_timestamp(tm.sec, 0u32),
};
- Ok(self
+ let response = self
.quotes
.write()
.insert_quote(&quote)
- .map(|()| "Successfully added!")?)
+ .map(|()| "Successfully added!")?;
+
+ Ok(response)
}
fn add(&self, command: &mut PluginCommand) -> Result<&str, QuoteError> {
@@ -85,87 +98,185 @@ impl<T: Database, C: Client> Quote<T, C> {
fn get(&self, command: &PluginCommand) -> Result<String, QuoteError> {
let quotee = &command.tokens.get(0);
let channel = &command.target;
- let count = if let Some(quotee) = quotee {
- self.quotes.read().count_user_quotes(quotee, channel)?
- } else {
- self.quotes.read().count_channel_quotes(channel)?
- };
+ match quotee {
+ Some(quotee) => {
+ let idx = match command.tokens.get(1) {
+ Some(s) => Some(i32::from_str(s).context(ErrorKind::InvalidIndex)?),
+ None => None,
+ };
+
+ self.get_user(quotee, channel, idx)
+ }
+ None => self.get_random(channel),
+ }
+ }
+
+ fn get_user(
+ &self,
+ quotee: &str,
+ channel: &str,
+ idx: Option<i32>,
+ ) -> Result<String, QuoteError> {
+ let count = self.quotes.read().count_user_quotes(quotee, channel)?;
if count < 1 {
Err(ErrorKind::NotFound)?;
}
- let len = command.tokens.len();
- let idx = if len < 2 || command.tokens[1].is_empty() {
- thread_rng().gen_range(1, count + 1)
+ let mut idx = if let Some(idx) = idx {
+ self.previous_map.lock().insert(
+ channel.to_owned(),
+ PreviousCommand::GetUser(quotee.to_owned(), Some(idx)),
+ );
+
+ idx
} else {
- let idx_string = &command.tokens[1];
- let idx = i32::from_str(idx_string).context(ErrorKind::InvalidIndex)?;
+ self.previous_map.lock().insert(
+ channel.to_owned(),
+ PreviousCommand::GetUser(quotee.to_owned(), None),
+ );
- if idx < 0 {
- count + idx + 1
- } else {
- idx
- }
+ thread_rng().gen_range(1, count + 1)
};
- let response = if let Some(quotee) = quotee {
- let quote = self
- .quotes
- .read()
- .get_user_quote(quotee, channel, idx)
- .context(ErrorKind::NotFound)?;
-
- format!(
- "\"{}\" - {}[{}/{}]",
- quote.content, quote.quotee, quote.idx, count
- )
- } else {
- let quote = self
- .quotes
- .read()
- .get_channel_quote(channel, idx)
- .context(ErrorKind::NotFound)?;
+ if idx < 0 {
+ idx += count + 1;
+ }
- format!("\"{}\" - {}[{}]", quote.content, quote.quotee, quote.idx)
- };
+ let quote = self
+ .quotes
+ .read()
+ .get_user_quote(quotee, channel, idx)
+ .context(ErrorKind::NotFound)?;
+
+ let response = format!(
+ "\"{}\" - {}[{}/{}]",
+ quote.content, quote.quotee, quote.idx, count
+ );
Ok(response)
}
+ fn get_random(&self, channel: &str) -> Result<String, QuoteError> {
+ let count = self.quotes.read().count_channel_quotes(channel)?;
+
+ if count < 1 {
+ Err(ErrorKind::NotFound)?;
+ }
+ self.previous_map
+ .lock()
+ .insert(channel.to_owned(), PreviousCommand::Get);
+
+ let idx = thread_rng().gen_range(1, count + 1);
+
+ let quote = self
+ .quotes
+ .read()
+ .get_channel_quote(channel, idx)
+ .context(ErrorKind::NotFound)?;
+
+ Ok(format!(
+ "\"{}\" - {}[{}]",
+ quote.content, quote.quotee, quote.idx
+ ))
+ }
+
fn search(&self, command: &mut PluginCommand) -> Result<String, QuoteError> {
if command.tokens.len() < 2 {
Err(ErrorKind::InvalidCommand)?;
}
- let user = match command.tokens.remove(0).deref() {
- "user" => Some(command.tokens.remove(0)),
- "channel" => None,
- _ => return Err(ErrorKind::InvalidCommand.into()),
- };
let channel = &command.target;
+ match command.tokens.remove(0).deref() {
+ "user" => {
+ let user = command.tokens.remove(0);
- if command.tokens.is_empty() {
- Err(ErrorKind::InvalidCommand)?;
+ if command.tokens.is_empty() {
+ Err(ErrorKind::InvalidCommand)?;
+ }
+
+ let query = command.tokens.join(" ");
+ self.search_user(&user, channel, &query, 0)
+ }
+ "channel" => {
+ if command.tokens.is_empty() {
+ Err(ErrorKind::InvalidCommand)?;
+ }
+
+ let query = command.tokens.join(" ");
+ self.search_channel(channel, &query, 0)
+ }
+ _ => Err(ErrorKind::InvalidCommand.into()),
}
+ }
- let query = command.tokens.join(" ");
- let quote = if let Some(user) = user {
- self.quotes
- .read()
- .search_user_quote(&query, &user, channel, 0)
- .context(ErrorKind::NotFound)?
- } else {
- self.quotes
- .read()
- .search_channel_quote(&query, channel, 0)
- .context(ErrorKind::NotFound)?
- };
+ fn next(&self, channel: String) -> Result<String, QuoteError> {
+ let previous = self
+ .previous_map
+ .lock()
+ .get(&channel)
+ .cloned()
+ .ok_or(ErrorKind::NoPrevious)?;
- Ok(format!(
- "\"{}\" - {}[{}]",
- quote.content, quote.quotee, quote.idx
- ))
+ match previous {
+ PreviousCommand::Get => self.get_random(&channel),
+ PreviousCommand::GetUser(user, idx) => {
+ let idx = idx.map(|idx| if idx < 0 { idx - 1 } else { idx + 1 });
+
+ self.get_user(&user, &channel, idx)
+ }
+ PreviousCommand::Search(query, offset) => {
+ self.search_channel(&channel, &query, offset + 1)
+ }
+ PreviousCommand::SearchUser(user, query, offset) => {
+ self.search_user(&user, &channel, &query, offset + 1)
+ }
+ }
+ }
+
+ fn search_user(
+ &self,
+ user: &str,
+ channel: &str,
+ query: &str,
+ offset: i32,
+ ) -> Result<String, QuoteError> {
+ self.previous_map.lock().insert(
+ channel.to_owned(),
+ PreviousCommand::SearchUser(user.to_owned(), query.to_owned(), offset),
+ );
+
+ let quote = self
+ .quotes
+ .read()
+ .search_user_quote(&query, &user, channel, offset)
+ .context(ErrorKind::NotFound)?;
+
+ let response = format!("\"{}\" - {}[{}]", quote.content, quote.quotee, quote.idx);
+
+ Ok(response)
+ }
+
+ fn search_channel(
+ &self,
+ channel: &str,
+ query: &str,
+ offset: i32,
+ ) -> Result<String, QuoteError> {
+ self.previous_map.lock().insert(
+ channel.to_owned(),
+ PreviousCommand::Search(query.to_owned(), offset),
+ );
+
+ let quote = self
+ .quotes
+ .read()
+ .search_channel_quote(&query, channel, offset)
+ .context(ErrorKind::NotFound)?;
+
+ let response = format!("\"{}\" - {}[{}]", quote.content, quote.quotee, quote.idx);
+
+ Ok(response)
}
fn info(&self, command: &PluginCommand) -> Result<String, QuoteError> {
@@ -223,7 +334,7 @@ impl<T: Database, C: Client> Quote<T, C> {
fn help(&self) -> &str {
"usage: quotes <subcommand>\r\n\
- subcommands: add, get, search info, help"
+ subcommands: add, get, search, next, info, help"
}
}
@@ -260,6 +371,7 @@ impl<T: Database, C: FrippyClient> Plugin for Quote<T, C> {
"add" => self.add(&mut command).map(|s| Private(s.to_owned())),
"get" => self.get(&command).map(Public),
"search" => self.search(&mut command).map(Public),
+ "next" => self.next(command.target).map(Public),
"info" => self.info(&command).map(Public),
"help" => Ok(Private(self.help().to_owned())),
_ => Err(ErrorKind::InvalidCommand.into()),
@@ -314,6 +426,10 @@ pub mod error {
#[fail(display = "Invalid index")]
InvalidIndex,
+ /// No previous command error
+ #[fail(display = "No previous command was found for this channel")]
+ NoPrevious,
+
/// Private message error
#[fail(display = "You can only add quotes in channel messages")]
PrivateMessageNotAllowed,