aboutsummaryrefslogtreecommitdiffstats
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
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
-rw-r--r--Cargo.lock11
-rw-r--r--Cargo.toml5
-rw-r--r--bin/main.rs23
-rw-r--r--configs/config.toml (renamed from config.toml)0
-rw-r--r--src/lib.rs184
5 files changed, 170 insertions, 53 deletions
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)",
]
@@ -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"
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/configs/config.toml
index 31049f9..31049f9 100644
--- a/config.toml
+++ b/configs/config.toml
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> {