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 /src | |
| 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
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 184 |
1 files changed, 131 insertions, 53 deletions
@@ -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> { |
