diff options
| author | Jokler <jokler.contact@gmail.com> | 2017-10-16 00:33:58 +0200 |
|---|---|---|
| committer | Jokler <jokler.contact@gmail.com> | 2017-10-16 00:33:58 +0200 |
| commit | a815a897c60a3c9d098b40a39e3d0549d5230b88 (patch) | |
| tree | 1de4e9e1715bf231928c49ab9ceca14a95cd3a20 | |
| parent | 4130d9b299265df7c06a9dcfa426746a870be615 (diff) | |
| download | frippy-a815a897c60a3c9d098b40a39e3d0549d5230b88.tar.gz frippy-a815a897c60a3c9d098b40a39e3d0549d5230b88.zip | |
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
| -rw-r--r-- | Cargo.lock | 11 | ||||
| -rw-r--r-- | Cargo.toml | 5 | ||||
| -rw-r--r-- | bin/main.rs | 23 | ||||
| -rw-r--r-- | configs/config.toml (renamed from config.toml) | 0 | ||||
| -rw-r--r-- | src/lib.rs | 184 |
5 files changed, 170 insertions, 53 deletions
@@ -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)", ] @@ -316,6 +321,11 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -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" @@ -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/configs/config.toml index 31049f9..31049f9 100644 --- a/config.toml +++ b/configs/config.toml @@ -12,20 +12,29 @@ //! ``` #[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<Arc<Mutex<Plugin>>> = @@ -56,72 +84,122 @@ pub fn run() { // if they use an incorrect plugin name let plugin_names: Vec<String> = 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<Arc<Mutex<Plugin>>>, + 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> { |
