summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJokler <jokler.contact@gmail.com>2017-10-16 00:33:58 +0200
committerJokler <jokler.contact@gmail.com>2017-10-16 00:33:58 +0200
commita815a897c60a3c9d098b40a39e3d0549d5230b88 (patch)
tree1de4e9e1715bf231928c49ab9ceca14a95cd3a20 /src
parent4130d9b299265df7c06a9dcfa426746a870be615 (diff)
downloadfrippy-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.rs184
1 files changed, 131 insertions, 53 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 873358a..379d0bd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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> {