diff --git a/src/lib.rs b/src/lib.rs index bee5ce2..f7d5c08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,9 +5,9 @@ extern crate discord; use std::collections::BTreeMap; use toml::Table; -mod plugins; -use plugins::Plugin; -use plugins::loader::{PluginLoader, PluginLoaderError}; +mod modules; +use modules::Module; +use modules::loader::{ModuleLoader, ModuleLoaderError}; mod event; use event::Event; @@ -17,54 +17,54 @@ use std::sync::mpsc; use std::sync::mpsc::Sender; pub struct Tenquestionmarks { - plugins: BTreeMap> + modules: BTreeMap> } impl Tenquestionmarks { - pub fn with_plugins (plugins: BTreeMap>) -> Tenquestionmarks { + pub fn with_modules (modules: BTreeMap>) -> Tenquestionmarks { let tqm = Tenquestionmarks { - plugins: plugins + modules: modules }; - for (key, plugin) in &tqm.plugins { - plugin.register(&tqm); + for (key, module) in &tqm.modules { + module.register(&tqm); } tqm } - pub fn from_configuration (configuration: Table) -> Result { - let loader = PluginLoader::new(); - let plugins = loader.load_from_configuration(configuration)?; - Result::Ok(Tenquestionmarks::with_plugins(plugins)) + pub fn from_configuration (configuration: Table) -> Result { + let loader = ModuleLoader::new(); + let modules = loader.load_from_configuration(configuration)?; + Result::Ok(Tenquestionmarks::with_modules(modules)) } pub fn run (&self) { crossbeam::scope(|scope| { // Our event channel. - // Plugins push events to tenquestionmarks using this channel. + // Modules push events to tenquestionmarks using this channel. let (ref sender, ref receiver) = mpsc::channel(); - // Plugin event consumer threads. - // tenquestionmarks propagates all events to each plugin through these + // Module event consumer threads. + // tenquestionmarks propagates all events to each Module through these // channels. - let senders: Vec> = self.plugins.values().map(|plugin| { + let senders: Vec> = self.modules.values().map(|module| { let (sender, receiver) = mpsc::channel(); - scope.spawn(move || plugin.consume_events(receiver)); + scope.spawn(move || module.consume_events(receiver)); sender }).collect(); - // Plugin event producer threads. - // Each plugin will produce events which tenquestionmarks will push - // into all other plugins. - for plugin in self.plugins.values() { - let plugin_sender = sender.clone(); - scope.spawn(move || plugin.produce_events(plugin_sender)); + // Module event producer threads. + // Each Module will produce events which tenquestionmarks will push + // into all other Modules. + for module in self.modules.values() { + let module_sender = sender.clone(); + scope.spawn(move || module.produce_events(module_sender)); } // tenquestionmarks main event loop. - // tenquestionmarks receives events produced by plugins and pushes them - // into all other plugins + // tenquestionmarks receives events produced by Modules and pushes them + // into all other Modules loop { match receiver.recv() { Ok(event) => { diff --git a/src/plugins/discord.rs b/src/modules/discord.rs similarity index 92% rename from src/plugins/discord.rs rename to src/modules/discord.rs index d859de9..dced3cf 100644 --- a/src/plugins/discord.rs +++ b/src/modules/discord.rs @@ -2,7 +2,7 @@ use discord; use discord::Discord; use discord::model::Event; -use plugins::Plugin; +use modules::Module; use toml::Table; use event; @@ -14,17 +14,17 @@ use MessageSender; use User; use Channel; -pub struct DiscordPlugin { +pub struct DiscordModule { token: String } -impl DiscordPlugin { - pub fn new (configuration: &Table) -> Box { +impl DiscordModule { + pub fn new (configuration: &Table) -> Box { let token = configuration.get("token") .and_then(|value| value.as_str()) .unwrap_or(""); - Box::new(DiscordPlugin { + Box::new(DiscordModule { token: String::from(token) }) } @@ -41,7 +41,7 @@ impl MessageSender for DiscordMessageSender { } } -impl Plugin for DiscordPlugin { +impl Module for DiscordModule { fn produce_events<'a>(&'a self, sender: Sender) { let discord = Arc::new(Discord::from_bot_token(&self.token[..]).expect("Login failed")); let (mut connection, _) = discord.connect().expect("Connection failed"); diff --git a/src/plugins/echo.rs b/src/modules/echo.rs similarity index 86% rename from src/plugins/echo.rs rename to src/modules/echo.rs index 00a8057..338e713 100644 --- a/src/plugins/echo.rs +++ b/src/modules/echo.rs @@ -1,26 +1,26 @@ -use plugins::Plugin; +use modules::Module; use toml::Table; use std::sync::mpsc::Receiver; use event::Event; -pub struct EchoPlugin { +pub struct EchoModule { prefix: String } -impl EchoPlugin { - pub fn new (configuration: &Table) -> Box { +impl EchoModule { + pub fn new (configuration: &Table) -> Box { let prefix = configuration.get("prefix") .and_then(|value| value.as_str()) .unwrap_or("!echo "); - Box::new(EchoPlugin { + Box::new(EchoModule { prefix: String::from(prefix) }) } } -impl Plugin for EchoPlugin { +impl Module for EchoModule { fn consume_events (&self, receiver: Receiver) { loop { match receiver.recv() { diff --git a/src/plugins/hello.rs b/src/modules/hello.rs similarity index 81% rename from src/plugins/hello.rs rename to src/modules/hello.rs index 72716ce..b728bbf 100644 --- a/src/plugins/hello.rs +++ b/src/modules/hello.rs @@ -1,4 +1,4 @@ -use plugins::Plugin; +use modules::Module; use toml::Table; use Tenquestionmarks; @@ -8,7 +8,7 @@ pub struct Hello { } impl Hello { - pub fn new (configuration: &Table) -> Box { + pub fn new (configuration: &Table) -> Box { let name = configuration.get("name") .and_then(|value| value.as_str()) .unwrap_or("world"); @@ -19,7 +19,7 @@ impl Hello { } } -impl Plugin for Hello { +impl Module for Hello { fn register (&self, tenquestionmarks: &Tenquestionmarks) { println!("Hello, {}!", self.name); } diff --git a/src/modules/loader.rs b/src/modules/loader.rs new file mode 100644 index 0000000..0f03b48 --- /dev/null +++ b/src/modules/loader.rs @@ -0,0 +1,74 @@ +use std::collections::BTreeMap; +use std::error::Error; +use std::fmt; + +use toml::Table; + +use modules::Module; +use modules::hello::Hello; +use modules::discord::DiscordModule; +use modules::lua::LuaModule; +use modules::stdin::StdinModule; +use modules::echo::EchoModule; + +pub struct ModuleLoader { + types: BTreeMap<&'static str, fn(&Table) -> Box> +} + +impl ModuleLoader { + pub fn new () -> ModuleLoader { + let mut types = BTreeMap::new(); + types.insert("hello", Hello::new as fn(&Table) -> Box); + types.insert("discord", DiscordModule::new as fn(&Table) -> Box); + types.insert("lua", LuaModule::new as fn(&Table) -> Box); + types.insert("stdin", StdinModule::new as fn(&Table) -> Box); + types.insert("echo", EchoModule::new as fn(&Table) -> Box); + ModuleLoader { + types: types + } + } + + pub fn load_from_configuration (&self, configuration: Table) -> Result>, ModuleLoaderError> { + configuration.into_iter().map(|(key, value)| { + match value.as_table() { + Some(table) => { + let module = self.load_single_module(&key, table)?; + Result::Ok((key, module)) + }, + None => Result::Err(ModuleLoaderError { message: format!("Bad configuration parameters for module instance: {}. Configuration for a Module must be a table.", key) }) + } + }).collect() + } + + pub fn load_single_module (&self, name: &str, configuration: &Table) -> Result, ModuleLoaderError> { + /* + * The Module type defaults to the instance name (in the tenquestionmarks configuration) + * but can explicitly be set by using the special "type" parameter. + */ + let module_type: &str = configuration.get("type") + .and_then(|value| value.as_str()) + .unwrap_or(name); + + match self.types.get(module_type) { + Some(constructor) => Result::Ok(constructor(configuration)), + None => Result::Err(ModuleLoaderError { message: format!("No such module type: {}", module_type) }) + } + } +} + +#[derive(Debug)] +pub struct ModuleLoaderError { + message: String +} + +impl Error for ModuleLoaderError { + fn description(&self) -> &str { + &self.message[..] + } +} + +impl fmt::Display for ModuleLoaderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ModuleLoaderError: {}", self.message) + } +} diff --git a/src/modules/lua.rs b/src/modules/lua.rs new file mode 100644 index 0000000..638e3ef --- /dev/null +++ b/src/modules/lua.rs @@ -0,0 +1,14 @@ +use modules::Module; +use toml::Table; + +pub struct LuaModule { + +} + +impl LuaModule { + pub fn new (configuration: &Table) -> Box { + Box::new(LuaModule {}) + } +} + +impl Module for LuaModule {} diff --git a/src/plugins/mod.rs b/src/modules/mod.rs similarity index 93% rename from src/plugins/mod.rs rename to src/modules/mod.rs index c1e434b..c3eb95f 100644 --- a/src/plugins/mod.rs +++ b/src/modules/mod.rs @@ -11,7 +11,7 @@ use event::Event; use std::sync::mpsc::{Sender, Receiver}; -pub trait Plugin : Sync { +pub trait Module : Sync { fn register (&self, tenquestionmarks: &Tenquestionmarks) {} fn consume_events (&self, receiver: Receiver) {} fn produce_events<'a>(&'a self, sender: Sender) {} diff --git a/src/plugins/stdin.rs b/src/modules/stdin.rs similarity index 84% rename from src/plugins/stdin.rs rename to src/modules/stdin.rs index 48711ca..c435989 100644 --- a/src/plugins/stdin.rs +++ b/src/modules/stdin.rs @@ -1,6 +1,6 @@ use std::io; -use plugins::Plugin; +use modules::Module; use toml::Table; use User; @@ -10,7 +10,7 @@ use std::sync::Arc; use std::sync::mpsc::Sender; use event::Event; -pub struct StdinPlugin {} +pub struct StdinModule {} pub struct StdinMessageSender { name: String @@ -22,13 +22,13 @@ impl MessageSender for StdinMessageSender { } } -impl StdinPlugin { - pub fn new (configuration: &Table) -> Box { - Box::new(StdinPlugin {}) +impl StdinModule { + pub fn new (configuration: &Table) -> Box { + Box::new(StdinModule {}) } } -impl Plugin for StdinPlugin { +impl Module for StdinModule { fn produce_events<'a>(&'a self, sender: Sender) { let user = User { name: String::from("Dave"), diff --git a/src/plugins/loader.rs b/src/plugins/loader.rs deleted file mode 100644 index e9f15c6..0000000 --- a/src/plugins/loader.rs +++ /dev/null @@ -1,74 +0,0 @@ -use std::collections::BTreeMap; -use std::error::Error; -use std::fmt; - -use toml::Table; - -use plugins::Plugin; -use plugins::hello::Hello; -use plugins::discord::DiscordPlugin; -use plugins::lua::LuaPlugin; -use plugins::stdin::StdinPlugin; -use plugins::echo::EchoPlugin; - -pub struct PluginLoader { - types: BTreeMap<&'static str, fn(&Table) -> Box> -} - -impl PluginLoader { - pub fn new () -> PluginLoader { - let mut types = BTreeMap::new(); - types.insert("hello", Hello::new as fn(&Table) -> Box); - types.insert("discord", DiscordPlugin::new as fn(&Table) -> Box); - types.insert("lua", LuaPlugin::new as fn(&Table) -> Box); - types.insert("stdin", StdinPlugin::new as fn(&Table) -> Box); - types.insert("echo", EchoPlugin::new as fn(&Table) -> Box); - PluginLoader { - types: types - } - } - - pub fn load_from_configuration (&self, configuration: Table) -> Result>, PluginLoaderError> { - configuration.into_iter().map(|(key, value)| { - match value.as_table() { - Some(table) => { - let plugin = self.load_single_plugin(&key, table)?; - Result::Ok((key, plugin)) - }, - None => Result::Err(PluginLoaderError { message: format!("Bad configuration parameters for plugin instance: {}. Configuration for a plugin must be a table.", key) }) - } - }).collect() - } - - pub fn load_single_plugin (&self, name: &str, configuration: &Table) -> Result, PluginLoaderError> { - /* - * The plugin type defaults to the instance name (in the tenquestionmarks configuration) - * but can explicitly be set by using the special "type" parameter. - */ - let plugin_type: &str = configuration.get("type") - .and_then(|value| value.as_str()) - .unwrap_or(name); - - match self.types.get(plugin_type) { - Some(constructor) => Result::Ok(constructor(configuration)), - None => Result::Err(PluginLoaderError { message: format!("No such plugin type: {}", plugin_type) }) - } - } -} - -#[derive(Debug)] -pub struct PluginLoaderError { - message: String -} - -impl Error for PluginLoaderError { - fn description(&self) -> &str { - &self.message[..] - } -} - -impl fmt::Display for PluginLoaderError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "PluginLoaderError: {}", self.message) - } -} diff --git a/src/plugins/lua.rs b/src/plugins/lua.rs deleted file mode 100644 index 11edacb..0000000 --- a/src/plugins/lua.rs +++ /dev/null @@ -1,14 +0,0 @@ -use plugins::Plugin; -use toml::Table; - -pub struct LuaPlugin { - -} - -impl LuaPlugin { - pub fn new (configuration: &Table) -> Box { - Box::new(LuaPlugin {}) - } -} - -impl Plugin for LuaPlugin {}