rename plugin -> module
This commit is contained in:
parent
bdee07143b
commit
0a51c7294f
50
src/lib.rs
50
src/lib.rs
@ -5,9 +5,9 @@ extern crate discord;
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
mod plugins;
|
mod modules;
|
||||||
use plugins::Plugin;
|
use modules::Module;
|
||||||
use plugins::loader::{PluginLoader, PluginLoaderError};
|
use modules::loader::{ModuleLoader, ModuleLoaderError};
|
||||||
|
|
||||||
mod event;
|
mod event;
|
||||||
use event::Event;
|
use event::Event;
|
||||||
@ -17,54 +17,54 @@ use std::sync::mpsc;
|
|||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
pub struct Tenquestionmarks {
|
pub struct Tenquestionmarks {
|
||||||
plugins: BTreeMap<String, Box<Plugin>>
|
modules: BTreeMap<String, Box<Module>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tenquestionmarks {
|
impl Tenquestionmarks {
|
||||||
pub fn with_plugins (plugins: BTreeMap<String, Box<Plugin>>) -> Tenquestionmarks {
|
pub fn with_modules (modules: BTreeMap<String, Box<Module>>) -> Tenquestionmarks {
|
||||||
let tqm = Tenquestionmarks {
|
let tqm = Tenquestionmarks {
|
||||||
plugins: plugins
|
modules: modules
|
||||||
};
|
};
|
||||||
|
|
||||||
for (key, plugin) in &tqm.plugins {
|
for (key, module) in &tqm.modules {
|
||||||
plugin.register(&tqm);
|
module.register(&tqm);
|
||||||
}
|
}
|
||||||
|
|
||||||
tqm
|
tqm
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_configuration (configuration: Table) -> Result<Tenquestionmarks, PluginLoaderError> {
|
pub fn from_configuration (configuration: Table) -> Result<Tenquestionmarks, ModuleLoaderError> {
|
||||||
let loader = PluginLoader::new();
|
let loader = ModuleLoader::new();
|
||||||
let plugins = loader.load_from_configuration(configuration)?;
|
let modules = loader.load_from_configuration(configuration)?;
|
||||||
Result::Ok(Tenquestionmarks::with_plugins(plugins))
|
Result::Ok(Tenquestionmarks::with_modules(modules))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run (&self) {
|
pub fn run (&self) {
|
||||||
crossbeam::scope(|scope| {
|
crossbeam::scope(|scope| {
|
||||||
// Our event channel.
|
// 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();
|
let (ref sender, ref receiver) = mpsc::channel();
|
||||||
|
|
||||||
// Plugin event consumer threads.
|
// Module event consumer threads.
|
||||||
// tenquestionmarks propagates all events to each plugin through these
|
// tenquestionmarks propagates all events to each Module through these
|
||||||
// channels.
|
// channels.
|
||||||
let senders: Vec<Sender<Event>> = self.plugins.values().map(|plugin| {
|
let senders: Vec<Sender<Event>> = self.modules.values().map(|module| {
|
||||||
let (sender, receiver) = mpsc::channel();
|
let (sender, receiver) = mpsc::channel();
|
||||||
scope.spawn(move || plugin.consume_events(receiver));
|
scope.spawn(move || module.consume_events(receiver));
|
||||||
sender
|
sender
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
// Plugin event producer threads.
|
// Module event producer threads.
|
||||||
// Each plugin will produce events which tenquestionmarks will push
|
// Each Module will produce events which tenquestionmarks will push
|
||||||
// into all other plugins.
|
// into all other Modules.
|
||||||
for plugin in self.plugins.values() {
|
for module in self.modules.values() {
|
||||||
let plugin_sender = sender.clone();
|
let module_sender = sender.clone();
|
||||||
scope.spawn(move || plugin.produce_events(plugin_sender));
|
scope.spawn(move || module.produce_events(module_sender));
|
||||||
}
|
}
|
||||||
|
|
||||||
// tenquestionmarks main event loop.
|
// tenquestionmarks main event loop.
|
||||||
// tenquestionmarks receives events produced by plugins and pushes them
|
// tenquestionmarks receives events produced by Modules and pushes them
|
||||||
// into all other plugins
|
// into all other Modules
|
||||||
loop {
|
loop {
|
||||||
match receiver.recv() {
|
match receiver.recv() {
|
||||||
Ok(event) => {
|
Ok(event) => {
|
||||||
|
@ -2,7 +2,7 @@ use discord;
|
|||||||
use discord::Discord;
|
use discord::Discord;
|
||||||
use discord::model::Event;
|
use discord::model::Event;
|
||||||
|
|
||||||
use plugins::Plugin;
|
use modules::Module;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
use event;
|
use event;
|
||||||
@ -14,17 +14,17 @@ use MessageSender;
|
|||||||
use User;
|
use User;
|
||||||
use Channel;
|
use Channel;
|
||||||
|
|
||||||
pub struct DiscordPlugin {
|
pub struct DiscordModule {
|
||||||
token: String
|
token: String
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiscordPlugin {
|
impl DiscordModule {
|
||||||
pub fn new (configuration: &Table) -> Box<Plugin> {
|
pub fn new (configuration: &Table) -> Box<Module> {
|
||||||
let token = configuration.get("token")
|
let token = configuration.get("token")
|
||||||
.and_then(|value| value.as_str())
|
.and_then(|value| value.as_str())
|
||||||
.unwrap_or("");
|
.unwrap_or("");
|
||||||
|
|
||||||
Box::new(DiscordPlugin {
|
Box::new(DiscordModule {
|
||||||
token: String::from(token)
|
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<event::Event>) {
|
fn produce_events<'a>(&'a self, sender: Sender<event::Event>) {
|
||||||
let discord = Arc::new(Discord::from_bot_token(&self.token[..]).expect("Login failed"));
|
let discord = Arc::new(Discord::from_bot_token(&self.token[..]).expect("Login failed"));
|
||||||
let (mut connection, _) = discord.connect().expect("Connection failed");
|
let (mut connection, _) = discord.connect().expect("Connection failed");
|
@ -1,26 +1,26 @@
|
|||||||
use plugins::Plugin;
|
use modules::Module;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
use event::Event;
|
use event::Event;
|
||||||
|
|
||||||
pub struct EchoPlugin {
|
pub struct EchoModule {
|
||||||
prefix: String
|
prefix: String
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EchoPlugin {
|
impl EchoModule {
|
||||||
pub fn new (configuration: &Table) -> Box<Plugin> {
|
pub fn new (configuration: &Table) -> Box<Module> {
|
||||||
let prefix = configuration.get("prefix")
|
let prefix = configuration.get("prefix")
|
||||||
.and_then(|value| value.as_str())
|
.and_then(|value| value.as_str())
|
||||||
.unwrap_or("!echo ");
|
.unwrap_or("!echo ");
|
||||||
|
|
||||||
Box::new(EchoPlugin {
|
Box::new(EchoModule {
|
||||||
prefix: String::from(prefix)
|
prefix: String::from(prefix)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Plugin for EchoPlugin {
|
impl Module for EchoModule {
|
||||||
fn consume_events (&self, receiver: Receiver<Event>) {
|
fn consume_events (&self, receiver: Receiver<Event>) {
|
||||||
loop {
|
loop {
|
||||||
match receiver.recv() {
|
match receiver.recv() {
|
@ -1,4 +1,4 @@
|
|||||||
use plugins::Plugin;
|
use modules::Module;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
use Tenquestionmarks;
|
use Tenquestionmarks;
|
||||||
@ -8,7 +8,7 @@ pub struct Hello {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Hello {
|
impl Hello {
|
||||||
pub fn new (configuration: &Table) -> Box<Plugin> {
|
pub fn new (configuration: &Table) -> Box<Module> {
|
||||||
let name = configuration.get("name")
|
let name = configuration.get("name")
|
||||||
.and_then(|value| value.as_str())
|
.and_then(|value| value.as_str())
|
||||||
.unwrap_or("world");
|
.unwrap_or("world");
|
||||||
@ -19,7 +19,7 @@ impl Hello {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Plugin for Hello {
|
impl Module for Hello {
|
||||||
fn register (&self, tenquestionmarks: &Tenquestionmarks) {
|
fn register (&self, tenquestionmarks: &Tenquestionmarks) {
|
||||||
println!("Hello, {}!", self.name);
|
println!("Hello, {}!", self.name);
|
||||||
}
|
}
|
74
src/modules/loader.rs
Normal file
74
src/modules/loader.rs
Normal file
@ -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<Module>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleLoader {
|
||||||
|
pub fn new () -> ModuleLoader {
|
||||||
|
let mut types = BTreeMap::new();
|
||||||
|
types.insert("hello", Hello::new as fn(&Table) -> Box<Module>);
|
||||||
|
types.insert("discord", DiscordModule::new as fn(&Table) -> Box<Module>);
|
||||||
|
types.insert("lua", LuaModule::new as fn(&Table) -> Box<Module>);
|
||||||
|
types.insert("stdin", StdinModule::new as fn(&Table) -> Box<Module>);
|
||||||
|
types.insert("echo", EchoModule::new as fn(&Table) -> Box<Module>);
|
||||||
|
ModuleLoader {
|
||||||
|
types: types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_from_configuration (&self, configuration: Table) -> Result<BTreeMap<String, Box<Module>>, 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<Box<Module>, 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)
|
||||||
|
}
|
||||||
|
}
|
14
src/modules/lua.rs
Normal file
14
src/modules/lua.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use modules::Module;
|
||||||
|
use toml::Table;
|
||||||
|
|
||||||
|
pub struct LuaModule {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LuaModule {
|
||||||
|
pub fn new (configuration: &Table) -> Box<Module> {
|
||||||
|
Box::new(LuaModule {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module for LuaModule {}
|
@ -11,7 +11,7 @@ use event::Event;
|
|||||||
|
|
||||||
use std::sync::mpsc::{Sender, Receiver};
|
use std::sync::mpsc::{Sender, Receiver};
|
||||||
|
|
||||||
pub trait Plugin : Sync {
|
pub trait Module : Sync {
|
||||||
fn register (&self, tenquestionmarks: &Tenquestionmarks) {}
|
fn register (&self, tenquestionmarks: &Tenquestionmarks) {}
|
||||||
fn consume_events (&self, receiver: Receiver<Event>) {}
|
fn consume_events (&self, receiver: Receiver<Event>) {}
|
||||||
fn produce_events<'a>(&'a self, sender: Sender<Event>) {}
|
fn produce_events<'a>(&'a self, sender: Sender<Event>) {}
|
@ -1,6 +1,6 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use plugins::Plugin;
|
use modules::Module;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
use User;
|
use User;
|
||||||
@ -10,7 +10,7 @@ use std::sync::Arc;
|
|||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use event::Event;
|
use event::Event;
|
||||||
|
|
||||||
pub struct StdinPlugin {}
|
pub struct StdinModule {}
|
||||||
|
|
||||||
pub struct StdinMessageSender {
|
pub struct StdinMessageSender {
|
||||||
name: String
|
name: String
|
||||||
@ -22,13 +22,13 @@ impl MessageSender for StdinMessageSender {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdinPlugin {
|
impl StdinModule {
|
||||||
pub fn new (configuration: &Table) -> Box<Plugin> {
|
pub fn new (configuration: &Table) -> Box<Module> {
|
||||||
Box::new(StdinPlugin {})
|
Box::new(StdinModule {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Plugin for StdinPlugin {
|
impl Module for StdinModule {
|
||||||
fn produce_events<'a>(&'a self, sender: Sender<Event>) {
|
fn produce_events<'a>(&'a self, sender: Sender<Event>) {
|
||||||
let user = User {
|
let user = User {
|
||||||
name: String::from("Dave"),
|
name: String::from("Dave"),
|
@ -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<Plugin>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PluginLoader {
|
|
||||||
pub fn new () -> PluginLoader {
|
|
||||||
let mut types = BTreeMap::new();
|
|
||||||
types.insert("hello", Hello::new as fn(&Table) -> Box<Plugin>);
|
|
||||||
types.insert("discord", DiscordPlugin::new as fn(&Table) -> Box<Plugin>);
|
|
||||||
types.insert("lua", LuaPlugin::new as fn(&Table) -> Box<Plugin>);
|
|
||||||
types.insert("stdin", StdinPlugin::new as fn(&Table) -> Box<Plugin>);
|
|
||||||
types.insert("echo", EchoPlugin::new as fn(&Table) -> Box<Plugin>);
|
|
||||||
PluginLoader {
|
|
||||||
types: types
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_from_configuration (&self, configuration: Table) -> Result<BTreeMap<String, Box<Plugin>>, 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<Box<Plugin>, 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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
use plugins::Plugin;
|
|
||||||
use toml::Table;
|
|
||||||
|
|
||||||
pub struct LuaPlugin {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LuaPlugin {
|
|
||||||
pub fn new (configuration: &Table) -> Box<Plugin> {
|
|
||||||
Box::new(LuaPlugin {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Plugin for LuaPlugin {}
|
|
Loading…
x
Reference in New Issue
Block a user