From 26f823b19d791e93a38712457df9294f3d1d2224 Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 13 Oct 2017 16:32:14 +0200 Subject: Do not use regex to check for commands --- src/lib.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index e1ca7e3..c00d3ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,8 +11,6 @@ //! frippy::run(); //! ``` -#[macro_use] -extern crate lazy_static; #[macro_use] extern crate plugin_derive; @@ -24,7 +22,6 @@ mod plugins; use std::thread::spawn; use std::sync::{Arc, Mutex}; -use regex::Regex; use irc::client::prelude::*; use irc::proto::Command::PRIVMSG; use irc::error::Error as IrcError; @@ -141,24 +138,21 @@ fn get_command(nick: &str, message: &Message) -> Option { .map(ToOwned::to_owned) .collect(); - // Check if the message contained notthing but spaces + // Check if the message contained nothing but spaces if tokens.is_empty() { return None; } - // Only compile the regex once - // We assume that only ':' and ',' are used as suffixes on IRC - lazy_static! { - static ref RE: Regex = Regex::new("^[:,]*?$").unwrap(); - } - + // Commands start with our name if tokens[0].to_lowercase().starts_with(nick) { // Remove the bot's name from the first token tokens[0].drain(..nick.len()); - // If the regex does not match the message is not directed at the bot - if !RE.is_match(&tokens[0]) { + // We assume that only ':' and ',' are used as suffixes on IRC + // If there are any other chars we assume that it is not ment for the bot + tokens[0] = tokens[0].chars().filter(|&c| !":,".contains(c)).collect(); + if !tokens[0].is_empty() { return None; } -- cgit v1.2.3-70-g09d2 From b7a2b610cf989e1261dee4ae42ca9348fe0710e8 Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 13 Oct 2017 16:33:59 +0200 Subject: Do not filter out empty Strings This makes the command syntax more strict but allows plugins to recreate the original command by joining the tokens. --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index c00d3ca..cda4e39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,7 +134,6 @@ fn get_command(nick: &str, message: &Message) -> Option { // Split content by spaces and filter empty tokens let mut tokens: Vec = content .split(' ') - .filter(|&x| !x.is_empty()) .map(ToOwned::to_owned) .collect(); -- cgit v1.2.3-70-g09d2 From ee1e7dfae96af5a426176f396ca3a23706033c45 Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 13 Oct 2017 16:56:22 +0200 Subject: Remove now redundant check --- src/lib.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index cda4e39..c556a32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -137,11 +137,6 @@ fn get_command(nick: &str, message: &Message) -> Option { .map(ToOwned::to_owned) .collect(); - // Check if the message contained nothing but spaces - if tokens.is_empty() { - return None; - } - // Commands start with our name if tokens[0].to_lowercase().starts_with(nick) { -- cgit v1.2.3-70-g09d2 From bea4d2a63b15eb3f908d8612bdc94dca1829229f Mon Sep 17 00:00:00 2001 From: Jokler Date: Sat, 14 Oct 2017 04:44:26 +0200 Subject: Improve readability of the Currency plugin --- src/plugins/currency.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/plugins/currency.rs b/src/plugins/currency.rs index bb16cd9..c6f0b2f 100644 --- a/src/plugins/currency.rs +++ b/src/plugins/currency.rs @@ -82,6 +82,11 @@ impl Currency { } fn convert(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { + + if command.tokens.len() < 3 { + return self.invalid_command(server, &command); + } + let request = match self.eval_command(&command.tokens) { Some(request) => request, None => { @@ -103,7 +108,7 @@ impl Currency { } } - fn help(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { + fn help(&self, server: &IrcServer, command: &mut PluginCommand) -> Result<(), IrcError> { let help = format!("usage: {} currency value from_currency to_currency\r\n\ example: 1.5 eur usd\r\n\ available currencies: AUD, BGN, BRL, CAD, \ @@ -117,7 +122,7 @@ impl Currency { } fn invalid_command(&self, server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> { - let help = format!("Incorrect value. \ + let help = format!("Incorrect Command. \ Send \"{} help currency\" for help.", server.current_nickname()); @@ -134,18 +139,15 @@ impl Plugin for Currency { Ok(()) } - fn command(&mut self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { - if command.tokens.is_empty() { - self.invalid_command(server, &command) + fn command(&mut self, server: &IrcServer, mut command: PluginCommand) -> Result<(), IrcError> { - } else if command.tokens[0].to_lowercase() == "help" { - self.help(server, command) - - } else if command.tokens.len() >= 3 { - self.convert(server, command) + if command.tokens.is_empty() { + return self.invalid_command(server, &command); + } - } else { - self.invalid_command(server, &command) + match command.tokens[0].as_ref() { + "help" => self.help(server, &mut command), + _ => self.convert(server, command), } } } -- cgit v1.2.3-70-g09d2 From 4130d9b299265df7c06a9dcfa426746a870be615 Mon Sep 17 00:00:00 2001 From: Jokler Date: Sat, 14 Oct 2017 04:46:05 +0200 Subject: Adjust formatting with cargo fmt --- src/lib.rs | 14 ++++++++------ src/plugins/currency.rs | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index c556a32..873358a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,9 @@ pub fn run() { if let Some(mut c) = command.clone() { // Skip empty commands - if c.tokens.is_empty() { continue; } + if c.tokens.is_empty() { + continue; + } if lock_plugin!(plugin).name().to_lowercase() == c.tokens[0].to_lowercase() { @@ -132,10 +134,7 @@ fn get_command(nick: &str, message: &Message) -> Option { if let PRIVMSG(_, ref content) = message.command { // Split content by spaces and filter empty tokens - let mut tokens: Vec = content - .split(' ') - .map(ToOwned::to_owned) - .collect(); + let mut tokens: Vec = content.split(' ').map(ToOwned::to_owned).collect(); // Commands start with our name if tokens[0].to_lowercase().starts_with(nick) { @@ -145,7 +144,10 @@ fn get_command(nick: &str, message: &Message) -> Option { // We assume that only ':' and ',' are used as suffixes on IRC // If there are any other chars we assume that it is not ment for the bot - tokens[0] = tokens[0].chars().filter(|&c| !":,".contains(c)).collect(); + tokens[0] = tokens[0] + .chars() + .filter(|&c| !":,".contains(c)) + .collect(); if !tokens[0].is_empty() { return None; } diff --git a/src/plugins/currency.rs b/src/plugins/currency.rs index c6f0b2f..bc87592 100644 --- a/src/plugins/currency.rs +++ b/src/plugins/currency.rs @@ -116,7 +116,7 @@ impl Currency { IDR, ILS, INR, JPY, KRW, MXN, MYR, NOK, \ NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, \ TRY, USD, ZAR", - server.current_nickname()); + server.current_nickname()); server.send_notice(&command.source, &help) } -- cgit v1.2.3-70-g09d2 From a815a897c60a3c9d098b40a39e3d0549d5230b88 Mon Sep 17 00:00:00 2001 From: Jokler Date: Mon, 16 Oct 2017 00:33:58 +0200 Subject: Rewrite run() and add logging The logger is created in main.rs for now and just logs messages over println. Changes on run() - Added Log Messages - Allow multiple configs which create one IrcServer each - Use tokio-core to keep IrcServers in the main thread --- Cargo.lock | 11 ++++ Cargo.toml | 5 ++ bin/main.rs | 23 +++++++ config.toml | 25 ------- configs/config.toml | 25 +++++++ src/lib.rs | 184 +++++++++++++++++++++++++++++++++++++--------------- 6 files changed, 195 insertions(+), 78 deletions(-) delete mode 100644 config.toml create mode 100644 configs/config.toml (limited to 'src') diff --git a/Cargo.lock b/Cargo.lock index 2bb00c7..24af77d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,13 +3,18 @@ name = "frippy" version = "0.2.0" dependencies = [ "clippy 0.0.165 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "irc 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "plugin_derive 0.1.0", "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "unicode_names 0.1.7 (git+https://github.com/Jokler/unicode_names?branch=update-to-latest-unicode)", ] @@ -315,6 +320,11 @@ name = "getopts" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "glob" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "httparse" version = "1.2.3" @@ -1186,6 +1196,7 @@ dependencies = [ "checksum futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "05a23db7bd162d4e8265968602930c476f688f0c180b44bdaf55e0cb2c687558" "checksum futures-cpupool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e86f49cc0d92fe1b97a5980ec32d56208272cbb00f15044ea9e2799dde766fdf" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" +"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" "checksum hyper 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b45eac8b696d59491b079bd04fcb0f3488c0f6ed62dcb36bcfea8a543e9cdc3" "checksum hyper-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c81fa95203e2a6087242c38691a0210f23e9f3f8f944350bd676522132e2985" diff --git a/Cargo.toml b/Cargo.toml index f07b67c..fc88edc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,11 +20,16 @@ doc = false [dependencies] irc = "0.12.5" +tokio-core = "0.1.10" +futures = "0.1.16" +log = "0.3.8" +time = "0.1" reqwest = "0.8.0" regex = "0.2.2" lazy_static = "0.2.9" serde = "1.0.15" serde_json = "1.0.3" +glob = "0.2" plugin_derive = { path = "plugin_derive" } unicode_names = { git = 'https://github.com/Jokler/unicode_names', branch = 'update-to-latest-unicode' } diff --git a/bin/main.rs b/bin/main.rs index b974405..18f362e 100644 --- a/bin/main.rs +++ b/bin/main.rs @@ -1,5 +1,28 @@ extern crate frippy; +extern crate log; +extern crate time; + +use log::{LogRecord, LogLevel, LogLevelFilter, LogMetadata}; + +struct Logger; + +impl log::Log for Logger { + fn enabled(&self, metadata: &LogMetadata) -> bool { + metadata.level() <= LogLevel::Info + } + + fn log(&self, record: &LogRecord) { + if self.enabled(record.metadata()) { + println!("[{}]({}) {}", time::now().rfc822(), record.level(), record.args()); + } + } +} fn main() { + log::set_logger(|max_log_level| { + max_log_level.set(LogLevelFilter::Info); + Box::new(Logger) + }).unwrap(); + frippy::run(); } diff --git a/config.toml b/config.toml deleted file mode 100644 index 31049f9..0000000 --- a/config.toml +++ /dev/null @@ -1,25 +0,0 @@ -owners = [] -nickname = "frippy" -#nick_password = "" -alt_nicks = ["frippy_", "frippy__"] -realname = "frippy" -server = "" -#password = "" -port = 6697 -use_ssl = true -#cert_path = "cert.der" -encoding = "UTF-8" -channels = ["#frippy"] -umodes = "+B" -user_info = "IRC Bot" -version = "frippy v0.2.0" -source = "https://github.com/Mavulp/frippy" -#ping_time = 180 -#ping_timeout = 10 -#burst_window_length = 8 -#max_messages_in_burst = 15 -#should_ghost = false -#ghost_sequence = [] - -#[channel_keys] -#"#frippy" = "" diff --git a/configs/config.toml b/configs/config.toml new file mode 100644 index 0000000..31049f9 --- /dev/null +++ b/configs/config.toml @@ -0,0 +1,25 @@ +owners = [] +nickname = "frippy" +#nick_password = "" +alt_nicks = ["frippy_", "frippy__"] +realname = "frippy" +server = "" +#password = "" +port = 6697 +use_ssl = true +#cert_path = "cert.der" +encoding = "UTF-8" +channels = ["#frippy"] +umodes = "+B" +user_info = "IRC Bot" +version = "frippy v0.2.0" +source = "https://github.com/Mavulp/frippy" +#ping_time = 180 +#ping_timeout = 10 +#burst_window_length = 8 +#max_messages_in_burst = 15 +#should_ghost = false +#ghost_sequence = [] + +#[channel_keys] +#"#frippy" = "" diff --git a/src/lib.rs b/src/lib.rs index 873358a..379d0bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,21 +11,30 @@ //! frippy::run(); //! ``` +#[macro_use] +extern crate log; #[macro_use] extern crate plugin_derive; extern crate irc; -extern crate regex; +extern crate tokio_core; +extern crate futures; +extern crate glob; mod plugin; mod plugins; use std::thread::spawn; use std::sync::{Arc, Mutex}; +use glob::glob; + use irc::client::prelude::*; use irc::proto::Command::PRIVMSG; use irc::error::Error as IrcError; +use tokio_core::reactor::Core; +use futures::future; + use plugin::*; // Lock the mutex and ignore if it is poisoned @@ -44,8 +53,27 @@ macro_rules! lock_plugin { /// /// This blocks the current thread while the bot is running pub fn run() { - let server = IrcServer::new("config.toml").unwrap(); - server.identify().unwrap(); + + // Load all toml files in the configs directory + let mut configs = Vec::new(); + for toml in glob("configs/*.toml").unwrap() { + match toml { + Ok(path) => { + info!("Loading {}", path.to_str().unwrap()); + match Config::load(path) { + Ok(v) => configs.push(v), + Err(e) => error!("Incorrect config file {}", e), + } + }, + Err(e) => error!("Failed to read path {}", e), + } + } + + // Without configs the bot would just idle + if configs.is_empty() { + error!("No config file found"); + return; + } // The list of plugins in use let plugins: Vec>> = @@ -56,72 +84,122 @@ pub fn run() { // if they use an incorrect plugin name let plugin_names: Vec = plugins .iter() - .map(|p| p.lock().unwrap().name().to_lowercase()) + .map(|p| lock_plugin!(p).name().to_lowercase()) .collect(); - // The main loop over received messages - server - .for_each_incoming(|message| { - let message = Arc::new(message); - // Check for possible command and save the result for later - let command = get_command(&server.current_nickname().to_lowercase(), &message); + info!("Plugins loaded: {}", plugin_names.join(", ")); - // Check if the first token of the command is valid - if let Some(ref c) = command { - if c.tokens.is_empty() { - let help = format!("Use \"{} help\" to get help", server.current_nickname()); - server.send_notice(&c.source, &help).unwrap(); + // Create an event loop to run the connections on. + let mut reactor = Core::new().unwrap(); - } else if "help" == &c.tokens[0].to_lowercase() { - send_help_message(&server, c).unwrap(); + // Open a connection and add work for each config + for config in configs { + let fut = IrcServer::new_future(reactor.handle(), &config).unwrap(); - } else if !plugin_names.contains(&c.tokens[0].to_lowercase()) { + let server = match reactor.run(fut) { + Ok(v) => { + info!("Connected to server"); + v + } + Err(e) => { + error!("Failed to connect: {}", e); + return; + } + }; - let help = format!("\"{} {}\" is not a command, \ - try \"{0} help\" instead.", - server.current_nickname(), - c.tokens[0]); + match server.identify() { + Ok(_) => info!("Intentified"), + Err(e) => error!("Failed to identify: {}", e), + }; - server.send_notice(&c.source, &help).unwrap(); - } - } + // TODO Duplicate clone... + let plugins = plugins.clone(); + let plugin_names = plugin_names.clone(); - for plugin in plugins.clone() { - // Send the message to the plugin if the plugin needs it - if lock_plugin!(plugin).is_allowed(&server, &message) { + let task = server + .stream() + .for_each(move |message| process_msg(&server, &plugin_names, plugins.clone(), message)) + .map_err(|e| Err(e).unwrap()); - // Clone everything before the move - // The server uses an Arc internally too - let plugin = Arc::clone(&plugin); - let message = Arc::clone(&message); - let server = server.clone(); + reactor.handle().spawn(task); + } - // Execute the plugin in another thread - spawn(move || { lock_plugin!(plugin).execute(&server, &message).unwrap(); }); - } + // Run the main loop forever + reactor.run(future::empty::<(), ()>()).unwrap(); +} - // Check if the command is for this plugin - // Clone it for the move - if let Some(mut c) = command.clone() { +fn process_msg(server: &IrcServer, + plugin_names: &[String], + plugins: Vec>>, + message: Message) + -> Result<(), IrcError> { - // Skip empty commands - if c.tokens.is_empty() { - continue; - } + if let Command::JOIN(ref channel, _, _) = message.command { + info!("Joined {}", channel); + } - if lock_plugin!(plugin).name().to_lowercase() == c.tokens[0].to_lowercase() { + let message = Arc::new(message); + // Check for possible command and save the result for later + let command = get_command(&server.current_nickname().to_lowercase(), &message); - // The first token contains the name of the plugin - c.tokens.remove(0); + // Check if the first token of the command is valid + if let Some(ref c) = command { + if c.tokens.is_empty() { + let help = format!("Use \"{} help\" to get help", server.current_nickname()); + server.send_notice(&c.source, &help).unwrap(); - // Clone the server for the move - it uses an Arc internally - let server = server.clone(); - spawn(move || { lock_plugin!(plugin).command(&server, c).unwrap(); }); - } - } + } else if "help" == &c.tokens[0].to_lowercase() { + send_help_message(server, c).unwrap(); + + } else if !plugin_names.contains(&c.tokens[0].to_lowercase()) { + + let help = format!("\"{} {}\" is not a command, \ + try \"{0} help\" instead.", + server.current_nickname(), + c.tokens[0]); + + server.send_notice(&c.source, &help).unwrap(); + } + } + + for plugin in plugins { + // Send the message to the plugin if the plugin needs it + if lock_plugin!(plugin).is_allowed(server, &message) { + + // Clone everything before the move + // The server uses an Arc internally too + let plugin = Arc::clone(&plugin); + let message = Arc::clone(&message); + let server = server.clone(); + + // Execute the plugin in another thread + spawn(move || { lock_plugin!(plugin).execute(&server, &message).unwrap(); }); + } + + // Check if the command is for this plugin + if let Some(mut c) = command.clone() { + + // Skip empty commands + if c.tokens.is_empty() { + continue; + } + + if lock_plugin!(plugin).name().to_lowercase() == c.tokens[0].to_lowercase() { + + // The first token contains the name of the plugin + let name = c.tokens.remove(0); + + // Clone the server for the move - it uses an Arc internally + let server = server.clone(); + spawn(move || { + if let Err(e) = lock_plugin!(plugin).command(&server, c) { + error!("Error in {} - {}", name, e); + }; + }); } - }) - .unwrap(); + } + } + Ok(()) } fn send_help_message(server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> { -- cgit v1.2.3-70-g09d2 From 513aa57334536dabc7a22856bbb99bc92ff1038f Mon Sep 17 00:00:00 2001 From: Jokler Date: Mon, 16 Oct 2017 00:50:24 +0200 Subject: Fix typo --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 379d0bd..11490d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,7 +108,7 @@ pub fn run() { }; match server.identify() { - Ok(_) => info!("Intentified"), + Ok(_) => info!("Identified"), Err(e) => error!("Failed to identify: {}", e), }; -- cgit v1.2.3-70-g09d2 From 292805ff70b6b39adfaeb0ffafed8626169b7bee Mon Sep 17 00:00:00 2001 From: Jokler Date: Tue, 17 Oct 2017 01:04:41 +0200 Subject: Display possible error when trying to create a connection This can still panic but that should be fixed in the next version of the irc library. --- src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 11490d4..f8534be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,7 +94,13 @@ pub fn run() { // Open a connection and add work for each config for config in configs { - let fut = IrcServer::new_future(reactor.handle(), &config).unwrap(); + let fut = match IrcServer::new_future(reactor.handle(), &config) { + Ok(v) => v, + Err(e) => { + error!("Failed to connect: {}", e); + return; + } + }; let server = match reactor.run(fut) { Ok(v) => { -- cgit v1.2.3-70-g09d2 From 8b64bdc7a96a1b5f4549493fb30042e1a46349a6 Mon Sep 17 00:00:00 2001 From: Jokler Date: Tue, 17 Oct 2017 04:24:32 +0200 Subject: Check if it was actually us who joined for the info message --- src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index f8534be..cc9f016 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -141,7 +141,9 @@ fn process_msg(server: &IrcServer, -> Result<(), IrcError> { if let Command::JOIN(ref channel, _, _) = message.command { - info!("Joined {}", channel); + if message.source_nickname().unwrap() == server.current_nickname() { + info!("Joined {}", channel); + } } let message = Arc::new(message); -- cgit v1.2.3-70-g09d2 From 44cec3059fcc5697f7347260eb77a952cfca18ab Mon Sep 17 00:00:00 2001 From: Jokler Date: Tue, 17 Oct 2017 05:14:40 +0200 Subject: Remove a few unwraps and make error handling more concise --- src/lib.rs | 43 ++++++++++++++++++++----------------------- src/plugins/currency.rs | 7 +------ 2 files changed, 21 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index cc9f016..da36d91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ pub fn run() { Ok(v) => configs.push(v), Err(e) => error!("Incorrect config file {}", e), } - }, + } Err(e) => error!("Failed to read path {}", e), } } @@ -94,24 +94,16 @@ pub fn run() { // Open a connection and add work for each config for config in configs { - let fut = match IrcServer::new_future(reactor.handle(), &config) { - Ok(v) => v, - Err(e) => { - error!("Failed to connect: {}", e); - return; - } - }; + let server = + match IrcServer::new_future(reactor.handle(), &config).and_then(|f| reactor.run(f)) { + Ok(v) => v, + Err(e) => { + error!("Failed to connect: {}", e); + return; + } + }; - let server = match reactor.run(fut) { - Ok(v) => { - info!("Connected to server"); - v - } - Err(e) => { - error!("Failed to connect: {}", e); - return; - } - }; + info!("Connected to server"); match server.identify() { Ok(_) => info!("Identified"), @@ -125,7 +117,7 @@ pub fn run() { let task = server .stream() .for_each(move |message| process_msg(&server, &plugin_names, plugins.clone(), message)) - .map_err(|e| Err(e).unwrap()); + .map_err(|e| error!("Failed to process message: {}", e)); reactor.handle().spawn(task); } @@ -154,10 +146,10 @@ fn process_msg(server: &IrcServer, if let Some(ref c) = command { if c.tokens.is_empty() { let help = format!("Use \"{} help\" to get help", server.current_nickname()); - server.send_notice(&c.source, &help).unwrap(); + server.send_notice(&c.source, &help)?; } else if "help" == &c.tokens[0].to_lowercase() { - send_help_message(server, c).unwrap(); + send_help_message(server, c)?; } else if !plugin_names.contains(&c.tokens[0].to_lowercase()) { @@ -166,7 +158,7 @@ fn process_msg(server: &IrcServer, server.current_nickname(), c.tokens[0]); - server.send_notice(&c.source, &help).unwrap(); + server.send_notice(&c.source, &help)?; } } @@ -181,7 +173,12 @@ fn process_msg(server: &IrcServer, let server = server.clone(); // Execute the plugin in another thread - spawn(move || { lock_plugin!(plugin).execute(&server, &message).unwrap(); }); + spawn(move || { + if let Err(e) = lock_plugin!(plugin).execute(&server, &message) { + let name = lock_plugin!(plugin).name().to_string(); + error!("Error in {} - {}", name, e); + }; + }); } // Check if the command is for this plugin diff --git a/src/plugins/currency.rs b/src/plugins/currency.rs index bc87592..0db8240 100644 --- a/src/plugins/currency.rs +++ b/src/plugins/currency.rs @@ -67,12 +67,7 @@ impl Currency { } fn eval_command<'a>(&self, tokens: &'a [String]) -> Option> { - let parsed = match tokens[0].parse() { - Ok(v) => v, - Err(_) => { - return None; - } - }; + let parsed = tokens[0].parse().ok()?; Some(ConvertionRequest { value: parsed, -- cgit v1.2.3-70-g09d2 From 8802b4a2839cb2e4d4cd2ed3d3e1b27ae4b250e6 Mon Sep 17 00:00:00 2001 From: Jokler Date: Tue, 17 Oct 2017 05:28:21 +0200 Subject: Handle one error in a verbose way again to support rust stable --- src/plugins/currency.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/plugins/currency.rs b/src/plugins/currency.rs index 0db8240..62ba847 100644 --- a/src/plugins/currency.rs +++ b/src/plugins/currency.rs @@ -67,13 +67,15 @@ impl Currency { } fn eval_command<'a>(&self, tokens: &'a [String]) -> Option> { - let parsed = tokens[0].parse().ok()?; - - Some(ConvertionRequest { - value: parsed, - source: &tokens[1], - target: &tokens[2], - }) + if let Some(parsed) = tokens[0].parse().ok() { + Some(ConvertionRequest { + value: parsed, + source: &tokens[1], + target: &tokens[2], + }) + } else { + None + } } fn convert(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { -- cgit v1.2.3-70-g09d2 From 8c51489bdd2d0c383c7d5b8e490cf2728702ba7b Mon Sep 17 00:00:00 2001 From: Jokler Date: Wed, 18 Oct 2017 15:42:00 +0200 Subject: Pass on a Result from the Currency eval function --- src/plugins/currency.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/plugins/currency.rs b/src/plugins/currency.rs index 62ba847..b15c852 100644 --- a/src/plugins/currency.rs +++ b/src/plugins/currency.rs @@ -4,8 +4,11 @@ extern crate serde_json; extern crate regex; use std::io::Read; +use std::num::ParseFloatError; + use irc::client::prelude::*; use irc::error::Error as IrcError; + use self::reqwest::Client; use self::reqwest::header::Connection; use self::serde_json::Value; @@ -66,16 +69,12 @@ impl Currency { Currency {} } - fn eval_command<'a>(&self, tokens: &'a [String]) -> Option> { - if let Some(parsed) = tokens[0].parse().ok() { - Some(ConvertionRequest { - value: parsed, - source: &tokens[1], - target: &tokens[2], - }) - } else { - None - } + fn eval_command<'a>(&self, tokens: &'a [String]) -> Result, ParseFloatError> { + Ok(ConvertionRequest { + value: tokens[0].parse()?, + source: &tokens[1], + target: &tokens[2], + }) } fn convert(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { @@ -85,8 +84,8 @@ impl Currency { } let request = match self.eval_command(&command.tokens) { - Some(request) => request, - None => { + Ok(request) => request, + Err(_) => { return self.invalid_command(server, &command); } }; -- cgit v1.2.3-70-g09d2 From 7e3b3fa74f5ddf9d69538b2c4f87e0288d0dcb9e Mon Sep 17 00:00:00 2001 From: Jokler Date: Thu, 26 Oct 2017 22:33:02 +0200 Subject: Make the Emoji plugin respond to messages in private chats --- src/plugins/emoji.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/emoji.rs b/src/plugins/emoji.rs index d2ed956..5d37feb 100644 --- a/src/plugins/emoji.rs +++ b/src/plugins/emoji.rs @@ -67,7 +67,9 @@ impl Plugin for Emoji { fn execute(&mut self, server: &IrcServer, message: &Message) -> Result<(), IrcError> { match message.command { - Command::PRIVMSG(ref target, ref content) => self.emoji(server, content, target), + Command::PRIVMSG(_, ref content) => { + self.emoji(server, content, message.response_target().unwrap()) + } _ => Ok(()), } } -- cgit v1.2.3-70-g09d2 From 4c6f2f088521cf0876b67f21a25e524983b7ada7 Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 27 Oct 2017 15:35:30 +0200 Subject: Fix currency response on bad command --- src/plugins/currency.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/currency.rs b/src/plugins/currency.rs index b15c852..fd447e3 100644 --- a/src/plugins/currency.rs +++ b/src/plugins/currency.rs @@ -119,7 +119,7 @@ impl Currency { fn invalid_command(&self, server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> { let help = format!("Incorrect Command. \ - Send \"{} help currency\" for help.", + Send \"{} currency help\" for help.", server.current_nickname()); server.send_notice(&command.source, &help) -- cgit v1.2.3-70-g09d2 From 0139861d1e41a765b6ffde7cae37c1e16f9c053c Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 27 Oct 2017 15:39:06 +0200 Subject: Refactor plugin management ThreadedPlugins should take care of anything Plugin related now. --- src/lib.rs | 150 +++++++--------------------------------------------------- src/plugin.rs | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 134 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index da36d91..55b121e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,29 +24,17 @@ extern crate glob; mod plugin; mod plugins; -use std::thread::spawn; -use std::sync::{Arc, Mutex}; -use glob::glob; +use std::sync::Arc; use irc::client::prelude::*; -use irc::proto::Command::PRIVMSG; use irc::error::Error as IrcError; use tokio_core::reactor::Core; use futures::future; +use glob::glob; use plugin::*; -// Lock the mutex and ignore if it is poisoned -macro_rules! lock_plugin { - ($e:expr) => { - match $e.lock() { - Ok(plugin) => plugin, - Err(poisoned) => poisoned.into_inner(), - } - } -} - /// Runs the bot /// /// # Remarks @@ -76,18 +64,10 @@ pub fn run() { } // The list of plugins in use - let plugins: Vec>> = - vec![Arc::new(Mutex::new(plugins::emoji::Emoji::new())), - Arc::new(Mutex::new(plugins::currency::Currency::new()))]; - - // We need the plugins' names to make sure the user gets a response - // if they use an incorrect plugin name - let plugin_names: Vec = plugins - .iter() - .map(|p| lock_plugin!(p).name().to_lowercase()) - .collect(); - - info!("Plugins loaded: {}", plugin_names.join(", ")); + let mut plugins = ThreadedPlugins::new(); + plugins.add(plugins::emoji::Emoji::new()); + plugins.add(plugins::currency::Currency::new()); + info!("Plugins loaded: {}", plugins); // Create an event loop to run the connections on. let mut reactor = Core::new().unwrap(); @@ -110,13 +90,12 @@ pub fn run() { Err(e) => error!("Failed to identify: {}", e), }; - // TODO Duplicate clone... + // TODO Verify if we actually need to clone plugins twice let plugins = plugins.clone(); - let plugin_names = plugin_names.clone(); let task = server .stream() - .for_each(move |message| process_msg(&server, &plugin_names, plugins.clone(), message)) + .for_each(move |message| process_msg(&server, plugins.clone(), message)) .map_err(|e| error!("Failed to process message: {}", e)); reactor.handle().spawn(task); @@ -127,8 +106,7 @@ pub fn run() { } fn process_msg(server: &IrcServer, - plugin_names: &[String], - plugins: Vec>>, + mut plugins: ThreadedPlugins, message: Message) -> Result<(), IrcError> { @@ -138,118 +116,22 @@ fn process_msg(server: &IrcServer, } } - let message = Arc::new(message); // Check for possible command and save the result for later - let command = get_command(&server.current_nickname().to_lowercase(), &message); + let command = PluginCommand::from(&server.current_nickname().to_lowercase(), &message); - // Check if the first token of the command is valid - if let Some(ref c) = command { - if c.tokens.is_empty() { - let help = format!("Use \"{} help\" to get help", server.current_nickname()); - server.send_notice(&c.source, &help)?; - - } else if "help" == &c.tokens[0].to_lowercase() { - send_help_message(server, c)?; - - } else if !plugin_names.contains(&c.tokens[0].to_lowercase()) { - - let help = format!("\"{} {}\" is not a command, \ - try \"{0} help\" instead.", - server.current_nickname(), - c.tokens[0]); + let message = Arc::new(message); + plugins.execute_plugins(server, message); - server.send_notice(&c.source, &help)?; + // If the message contained a command, handle it + if let Some(command) = command { + if let Err(e) = plugins.handle_command(server, command) { + error!("Failed to handle command: {}", e); } } - for plugin in plugins { - // Send the message to the plugin if the plugin needs it - if lock_plugin!(plugin).is_allowed(server, &message) { - - // Clone everything before the move - // The server uses an Arc internally too - let plugin = Arc::clone(&plugin); - let message = Arc::clone(&message); - let server = server.clone(); - - // Execute the plugin in another thread - spawn(move || { - if let Err(e) = lock_plugin!(plugin).execute(&server, &message) { - let name = lock_plugin!(plugin).name().to_string(); - error!("Error in {} - {}", name, e); - }; - }); - } - - // Check if the command is for this plugin - if let Some(mut c) = command.clone() { - - // Skip empty commands - if c.tokens.is_empty() { - continue; - } - - if lock_plugin!(plugin).name().to_lowercase() == c.tokens[0].to_lowercase() { - - // The first token contains the name of the plugin - let name = c.tokens.remove(0); - - // Clone the server for the move - it uses an Arc internally - let server = server.clone(); - spawn(move || { - if let Err(e) = lock_plugin!(plugin).command(&server, c) { - error!("Error in {} - {}", name, e); - }; - }); - } - } - } Ok(()) } -fn send_help_message(server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> { - server.send_notice(&command.source, "Help has not been added yet.") -} - -fn get_command(nick: &str, message: &Message) -> Option { - - // Get the actual message out of PRIVMSG - if let PRIVMSG(_, ref content) = message.command { - - // Split content by spaces and filter empty tokens - let mut tokens: Vec = content.split(' ').map(ToOwned::to_owned).collect(); - - // Commands start with our name - if tokens[0].to_lowercase().starts_with(nick) { - - // Remove the bot's name from the first token - tokens[0].drain(..nick.len()); - - // We assume that only ':' and ',' are used as suffixes on IRC - // If there are any other chars we assume that it is not ment for the bot - tokens[0] = tokens[0] - .chars() - .filter(|&c| !":,".contains(c)) - .collect(); - if !tokens[0].is_empty() { - return None; - } - - // The first token contained the name of the bot - tokens.remove(0); - - Some(PluginCommand { - source: message.source_nickname().unwrap().to_string(), - target: message.response_target().unwrap().to_string(), - tokens: tokens, - }) - } else { - None - } - } else { - None - } -} #[cfg(test)] mod tests {} diff --git a/src/plugin.rs b/src/plugin.rs index 0a4034d..d1a1f3d 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,4 +1,8 @@ use std::fmt; +use std::collections::HashMap; +use std::thread::spawn; +use std::sync::{Arc, Mutex}; + use irc::client::prelude::*; use irc::error::Error as IrcError; @@ -18,3 +22,147 @@ pub struct PluginCommand { pub target: String, pub tokens: Vec, } + +impl PluginCommand { + pub fn from(nick: &str, message: &Message) -> Option { + + // Get the actual message out of PRIVMSG + if let Command::PRIVMSG(_, ref content) = message.command { + + // Split content by spaces and filter empty tokens + let mut tokens: Vec = content.split(' ').map(ToOwned::to_owned).collect(); + + // Commands start with our name + if tokens[0].to_lowercase().starts_with(nick) { + + // Remove the bot's name from the first token + tokens[0].drain(..nick.len()); + + // We assume that only ':' and ',' are used as suffixes on IRC + // If there are any other chars we assume that it is not ment for the bot + tokens[0] = tokens[0] + .chars() + .filter(|&c| !":,".contains(c)) + .collect(); + if !tokens[0].is_empty() { + return None; + } + + // The first token contained the name of the bot + tokens.remove(0); + + Some(PluginCommand { + source: message.source_nickname().unwrap().to_string(), + target: message.response_target().unwrap().to_string(), + tokens: tokens, + }) + } else { + None + } + } else { + None + } + } +} + +// Lock the mutex and ignore if it is poisoned +macro_rules! lock_plugin { + ($e:expr) => { + match $e.lock() { + Ok(plugin) => plugin, + Err(poisoned) => poisoned.into_inner(), + } + } +} + +#[derive(Clone, Debug)] +pub struct ThreadedPlugins { + plugins: HashMap>>, +} + +impl ThreadedPlugins { + pub fn new() -> ThreadedPlugins { + ThreadedPlugins { plugins: HashMap::new() } + } + + pub fn add(&mut self, plugin: T) { + let name = plugin.name().to_lowercase(); + let safe_plugin = Arc::new(Mutex::new(plugin)); + + self.plugins.insert(name, safe_plugin); + } + + pub fn execute_plugins(&mut self, server: &IrcServer, message: Arc) { + + for (name, plugin) in self.plugins.clone() { + // Send the message to the plugin if the plugin needs it + if lock_plugin!(plugin).is_allowed(server, &message) { + + // Clone everything before the move + // The server uses an Arc internally too + let plugin = Arc::clone(&plugin); + let message = Arc::clone(&message); + let server = server.clone(); + + // Execute the plugin in another thread + spawn(move || { + if let Err(e) = lock_plugin!(plugin).execute(&server, &message) { + error!("Error in {} - {}", name, e); + }; + }); + } + } + } + + pub fn handle_command(&mut self, server: &IrcServer, mut command: PluginCommand) -> Result<(), IrcError> { + + if !command.tokens.iter().any(|s| !s.is_empty()) { + let help = format!("Use \"{} help\" to get help", server.current_nickname()); + return server.send_notice(&command.source, &help); + } + + if &command.tokens[0].to_lowercase() == "help" { + return self.send_help_message(server, &command); + } + + // Check if the command is for this plugin + if let Some(plugin) = self.plugins.get(&command.tokens[0].to_lowercase()) { + + // The first token contains the name of the plugin + let name = command.tokens.remove(0); + + // Clone for the move - the server uses an Arc internally + let server = server.clone(); + let plugin = Arc::clone(plugin); + spawn(move || { + if let Err(e) = lock_plugin!(plugin).command(&server, command) { + error!("Error in {} command - {}", name, e); + }; + }); + + Ok(()) + + } else { + let help = format!("\"{} {}\" is not a command, \ + try \"{0} help\" instead.", + server.current_nickname(), + command.tokens[0]); + + server.send_notice(&command.source, &help) + } + } + + fn send_help_message(&self, server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> { + server.send_notice(&command.source, "Help has not been added yet.") + } +} + +impl fmt::Display for ThreadedPlugins { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let plugin_names = self.plugins + .iter() + .map(|(_, p)| lock_plugin!(p).name().to_string()) + .collect::>(); + write!(f, "{}", plugin_names.join(", ")) + } +} -- cgit v1.2.3-70-g09d2 From afa5eb93e9e14b65e3c846e70e22c6134ca95f80 Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 27 Oct 2017 15:45:29 +0200 Subject: Panic if execute is called on the Currency Plugin --- src/plugins/currency.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/currency.rs b/src/plugins/currency.rs index fd447e3..78ae593 100644 --- a/src/plugins/currency.rs +++ b/src/plugins/currency.rs @@ -132,7 +132,7 @@ impl Plugin for Currency { } fn execute(&mut self, _: &IrcServer, _: &Message) -> Result<(), IrcError> { - Ok(()) + panic!("Currency does not implement the execute function!") } fn command(&mut self, server: &IrcServer, mut command: PluginCommand) -> Result<(), IrcError> { -- cgit v1.2.3-70-g09d2 From 8b481420cd3c0dd02cb5671e753dc5ff4a40e7eb Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 27 Oct 2017 15:55:11 +0200 Subject: Move help into a Plugin --- src/lib.rs | 1 + src/plugin.rs | 8 -------- src/plugins/mod.rs | 1 + 3 files changed, 2 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 55b121e..5b8d479 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,7 @@ pub fn run() { // The list of plugins in use let mut plugins = ThreadedPlugins::new(); + plugins.add(plugins::help::Help::new()); plugins.add(plugins::emoji::Emoji::new()); plugins.add(plugins::currency::Currency::new()); info!("Plugins loaded: {}", plugins); diff --git a/src/plugin.rs b/src/plugin.rs index d1a1f3d..e0a4ce2 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -121,10 +121,6 @@ impl ThreadedPlugins { return server.send_notice(&command.source, &help); } - if &command.tokens[0].to_lowercase() == "help" { - return self.send_help_message(server, &command); - } - // Check if the command is for this plugin if let Some(plugin) = self.plugins.get(&command.tokens[0].to_lowercase()) { @@ -151,10 +147,6 @@ impl ThreadedPlugins { server.send_notice(&command.source, &help) } } - - fn send_help_message(&self, server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> { - server.send_notice(&command.source, "Help has not been added yet.") - } } impl fmt::Display for ThreadedPlugins { diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index adf54b2..d07ead6 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,2 +1,3 @@ +pub mod help; pub mod emoji; pub mod currency; -- cgit v1.2.3-70-g09d2 From 2b943fa26f1d3c199cbc03e65c567e5c29887465 Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 27 Oct 2017 18:19:39 +0200 Subject: Add emoji counting --- src/plugins/emoji.rs | 67 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/plugins/emoji.rs b/src/plugins/emoji.rs index 5d37feb..99f6c26 100644 --- a/src/plugins/emoji.rs +++ b/src/plugins/emoji.rs @@ -1,43 +1,82 @@ extern crate unicode_names; +use std::fmt; + use irc::client::prelude::*; use irc::error::Error as IrcError; use plugin::*; +struct EmojiHandle { + symbol: char, + count: i32, +} + +impl fmt::Display for EmojiHandle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + + let name = match unicode_names::name(self.symbol) { + Some(sym) => sym.to_string().to_lowercase(), + None => String::from("UNKNOWN"), + }; + + if self.count > 1 { + write!(f, "{}x {}", self.count, name) + } else { + write!(f, "{}", name) + } + } +} + #[derive(PluginName, Debug)] pub struct Emoji; + impl Emoji { pub fn new() -> Emoji { Emoji {} } fn emoji(&self, server: &IrcServer, content: &str, target: &str) -> Result<(), IrcError> { - - let mut names: Vec = Vec::new(); - for emoji in self.return_emojis(content) { - - let name = match unicode_names::name(emoji) { - Some(v) => format!("{}", v).to_lowercase(), - None => "UNKNOWN".to_string(), - }; - - names.push(name); - } + let names = self.return_emojis(content) + .iter() + .map(|e| e.to_string()) + .collect::>(); server.send_privmsg(target, &names.join(", ")) } - fn return_emojis(&self, string: &str) -> Vec { + fn return_emojis(&self, string: &str) -> Vec { + + let mut emojis: Vec = Vec::new(); + + let mut current = EmojiHandle { + symbol: ' ', + count: 0, + }; - let mut emojis: Vec = Vec::new(); for c in string.chars() { if self.is_emoji(&c) { - emojis.push(c); + if current.symbol == c { + current.count = current.count + 1; + + } else { + if current.count > 0 { + emojis.push(current); + } + + current = EmojiHandle { + symbol: c, + count: 1, + } + } } } + if current.count > 0 { + emojis.push(current); + } + emojis } -- cgit v1.2.3-70-g09d2 From 9d77de5e5d133b990983040b01cc0cb22b2f526b Mon Sep 17 00:00:00 2001 From: Jokler Date: Fri, 27 Oct 2017 20:24:44 +0200 Subject: Add missing help plugin --- src/plugins/help.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/plugins/help.rs (limited to 'src') diff --git a/src/plugins/help.rs b/src/plugins/help.rs new file mode 100644 index 0000000..c4ddcd4 --- /dev/null +++ b/src/plugins/help.rs @@ -0,0 +1,34 @@ +use irc::client::prelude::*; +use irc::error::Error as IrcError; + +use plugin::*; + +#[derive(PluginName, Debug)] +pub struct Help; + +impl Help { + pub fn new() -> Help { + Help {} + } + + fn help(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { + server.send_notice(&command.source, "Help has not been added yet.") + } +} + +impl Plugin for Help { + fn is_allowed(&self, _: &IrcServer, _: &Message) -> bool { + false + } + + fn execute(&mut self, _: &IrcServer, _: &Message) -> Result<(), IrcError> { + panic!("Help does not implement the execute function!") + } + + fn command(&mut self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { + self.help(server, command) + } +} + +#[cfg(test)] +mod tests {} -- cgit v1.2.3-70-g09d2 From feafddfde3a42725db8f4d68eb6c6a8e5058ed87 Mon Sep 17 00:00:00 2001 From: Jokler Date: Sat, 28 Oct 2017 23:10:06 +0200 Subject: Document the usage of the log crate --- src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 5b8d479..d912973 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,12 +4,16 @@ //! Frippy is an IRC bot that runs plugins on each message //! received. //! -//! # Example +//! ## Example //! ```no_run //! extern crate frippy; //! //! frippy::run(); //! ``` +//! +//! # Logging +//! Frippy uses the [log](https://docs.rs/log) crate so you can log events +//! which might be of interest. #[macro_use] extern crate log; -- cgit v1.2.3-70-g09d2 From d203f2689ac7addf36a32150691f459212199f09 Mon Sep 17 00:00:00 2001 From: Jokler Date: Sat, 28 Oct 2017 23:34:30 +0200 Subject: Reformat the emoji counting loop --- src/plugins/emoji.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/plugins/emoji.rs b/src/plugins/emoji.rs index 99f6c26..09d5c27 100644 --- a/src/plugins/emoji.rs +++ b/src/plugins/emoji.rs @@ -46,7 +46,6 @@ impl Emoji { } fn return_emojis(&self, string: &str) -> Vec { - let mut emojis: Vec = Vec::new(); let mut current = EmojiHandle { @@ -56,19 +55,21 @@ impl Emoji { for c in string.chars() { - if self.is_emoji(&c) { - if current.symbol == c { - current.count = current.count + 1; - - } else { - if current.count > 0 { - emojis.push(current); - } - - current = EmojiHandle { - symbol: c, - count: 1, - } + if !self.is_emoji(&c) { + continue; + } + + if current.symbol == c { + current.count += 1; + + } else { + if current.count > 0 { + emojis.push(current); + } + + current = EmojiHandle { + symbol: c, + count: 1, } } } -- cgit v1.2.3-70-g09d2 From fa558e306d33750b391759affb9628b31693e572 Mon Sep 17 00:00:00 2001 From: Jokler Date: Sun, 29 Oct 2017 02:41:47 +0100 Subject: Export plugins directly instead of their modules --- src/lib.rs | 6 +++--- src/plugins/mod.rs | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index d912973..324e273 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,9 +69,9 @@ pub fn run() { // The list of plugins in use let mut plugins = ThreadedPlugins::new(); - plugins.add(plugins::help::Help::new()); - plugins.add(plugins::emoji::Emoji::new()); - plugins.add(plugins::currency::Currency::new()); + plugins.add(plugins::Help::new()); + plugins.add(plugins::Emoji::new()); + plugins.add(plugins::Currency::new()); info!("Plugins loaded: {}", plugins); // Create an event loop to run the connections on. diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index d07ead6..0dea596 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,3 +1,7 @@ -pub mod help; -pub mod emoji; -pub mod currency; +mod help; +mod emoji; +mod currency; + +pub use self::help::Help; +pub use self::emoji::Emoji; +pub use self::currency::Currency; -- cgit v1.2.3-70-g09d2