diff options
| author | Jokler <jokler.contact@gmail.com> | 2018-03-13 21:30:01 +0100 |
|---|---|---|
| committer | Jokler <jokler.contact@gmail.com> | 2018-03-13 21:30:01 +0100 |
| commit | 8a2180e2d7b73e9299c1e5ef46185558953b9613 (patch) | |
| tree | 956f115544973be78569da7d2609910037deab04 /src/plugins/sed.rs | |
| parent | edffba8b37e67722e450737a3723773f98dd923a (diff) | |
| download | frippy-8a2180e2d7b73e9299c1e5ef46185558953b9613.tar.gz frippy-8a2180e2d7b73e9299c1e5ef46185558953b9613.zip | |
Add missing plugin file
Diffstat (limited to 'src/plugins/sed.rs')
| -rw-r--r-- | src/plugins/sed.rs | 165 |
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, + } +} |
