aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJokler <jokler.contact@gmail.com>2018-03-13 21:30:01 +0100
committerJokler <jokler.contact@gmail.com>2018-03-13 21:30:01 +0100
commit8a2180e2d7b73e9299c1e5ef46185558953b9613 (patch)
tree956f115544973be78569da7d2609910037deab04
parentedffba8b37e67722e450737a3723773f98dd923a (diff)
downloadfrippy-8a2180e2d7b73e9299c1e5ef46185558953b9613.tar.gz
frippy-8a2180e2d7b73e9299c1e5ef46185558953b9613.zip
Add missing plugin file
-rw-r--r--src/plugins/sed.rs165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/plugins/sed.rs b/src/plugins/sed.rs
new file mode 100644
index 0000000..db47256
--- /dev/null
+++ b/src/plugins/sed.rs
@@ -0,0 +1,165 @@
+use std::sync::Mutex;
+use std::collections::HashMap;
+use circular_queue::CircularQueue;
+use regex::{Regex, RegexBuilder};
+
+use irc::client::prelude::*;
+
+use plugin::*;
+
+use failure::Fail;
+use failure::ResultExt;
+use error::ErrorKind as FrippyErrorKind;
+use error::FrippyError;
+use self::error::*;
+
+lazy_static! {
+ static ref RE: Regex = Regex::new(r"^s/((?:\\/|[^/])+)/((?:\\/|[^/])*)/(?:(\w+))?\s*$").unwrap();
+}
+
+#[derive(PluginName, Debug)]
+pub struct Sed {
+ per_channel: usize,
+ channel_messages: Mutex<HashMap<String, CircularQueue<String>>>,
+}
+
+macro_rules! try_lock {
+ ( $m:expr ) => {
+ match $m.lock() {
+ Ok(guard) => guard,
+ Err(poisoned) => poisoned.into_inner(),
+ }
+ }
+}
+
+impl Sed {
+ pub fn new(per_channel: usize) -> Sed {
+ Sed {
+ per_channel: per_channel,
+ channel_messages: Mutex::new(HashMap::new()),
+ }
+ }
+
+ fn add_message(&self, channel: String, message: String) {
+ let mut channel_messages = try_lock!(self.channel_messages);
+ let messages = channel_messages
+ .entry(channel)
+ .or_insert(CircularQueue::with_capacity(self.per_channel));
+ messages.push(message);
+ }
+
+ fn run_regex(&self, channel: &str, message: &str) -> Result<String, SedError> {
+ let mut global_match = false;
+ let mut case_insens = false;
+ let mut ign_whitespace = false;
+ let mut swap_greed = false;
+ let mut disable_unicode = false;
+
+ let captures = RE.captures(message).unwrap();
+ debug!("{:?}", captures);
+
+ let first = captures.get(1).unwrap().as_str();
+ let second = captures.get(2).unwrap().as_str();
+
+ if let Some(flags) = captures.get(3) {
+ let flags = flags.as_str();
+
+ global_match = flags.contains('g');
+ case_insens = flags.contains('i');
+ ign_whitespace = flags.contains('x');
+ disable_unicode = !flags.contains('u');
+ swap_greed = flags.contains('U');
+ }
+
+ let user_re = RegexBuilder::new(&first.replace(r"\/", "/"))
+ .case_insensitive(case_insens)
+ .ignore_whitespace(ign_whitespace)
+ .unicode(disable_unicode)
+ .swap_greed(swap_greed)
+ .build().context(ErrorKind::InvalidRegex)?;
+
+ let channel_messages = try_lock!(self.channel_messages);
+ let messages = channel_messages.get(channel).ok_or(ErrorKind::NoMessages)?;
+
+ for message in messages.iter() {
+ if user_re.is_match(message) {
+ let response = if global_match {
+ user_re.replace_all(message, second)
+ } else {
+ user_re.replace(message, second)
+ };
+
+ return Ok(response.to_string());
+ }
+ }
+
+ Err(ErrorKind::NoMatch)?
+ }
+}
+
+impl Plugin for Sed {
+ fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus {
+ match message.command {
+ Command::PRIVMSG(_, ref content) => {
+ let channel = message.response_target().unwrap();
+ if channel == message.source_nickname().unwrap() {
+ return ExecutionStatus::Done;
+ }
+
+ if RE.is_match(content) {
+ let result = match self.run_regex(channel, content) {
+ Ok(msg) => client.send_privmsg(channel, &msg),
+ Err(e) => client.send_notice(channel, &e.to_string()),
+ };
+
+ match result {
+ Err(e) => ExecutionStatus::Err(e.context(FrippyErrorKind::Connection).into()),
+ Ok(_) => ExecutionStatus::Done,
+ }
+ } else {
+ self.add_message(channel.to_string(), content.to_string());
+
+ ExecutionStatus::Done
+ }
+ }
+ _ => ExecutionStatus::Done,
+ }
+ }
+
+ fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> {
+ panic!("Sed should not use threading")
+ }
+
+ fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
+ Ok(client
+ .send_notice(
+ &command.source,
+ "Currently this Plugin does not implement any commands.",
+ )
+ .context(FrippyErrorKind::Connection)?)
+ }
+
+ fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
+ Err(String::from(
+ "Evaluation of commands is not implemented for sed at this time",
+ ))
+ }
+}
+
+pub mod error {
+ #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
+ #[error = "SedError"]
+ pub enum ErrorKind {
+ /// Invalid regex error
+ #[fail(display = "Invalid regex")]
+ InvalidRegex,
+
+ /// No messages found error
+ #[fail(display = "No messages were found for this channel")]
+ NoMessages,
+
+ /// No match found error
+ #[fail(display = "No recent messages match this regex")]
+ NoMatch,
+ }
+}