rename plugin -> module
This commit is contained in:
80
src/modules/discord.rs
Normal file
80
src/modules/discord.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use discord;
|
||||
use discord::Discord;
|
||||
use discord::model::Event;
|
||||
|
||||
use modules::Module;
|
||||
use toml::Table;
|
||||
|
||||
use event;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use MessageSender;
|
||||
use User;
|
||||
use Channel;
|
||||
|
||||
pub struct DiscordModule {
|
||||
token: String
|
||||
}
|
||||
|
||||
impl DiscordModule {
|
||||
pub fn new (configuration: &Table) -> Box<Module> {
|
||||
let token = configuration.get("token")
|
||||
.and_then(|value| value.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
Box::new(DiscordModule {
|
||||
token: String::from(token)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DiscordMessageSender {
|
||||
discord: Arc<Discord>,
|
||||
channel_id: discord::model::ChannelId
|
||||
}
|
||||
|
||||
impl MessageSender for DiscordMessageSender {
|
||||
fn send_message (&self, message: &str) {
|
||||
self.discord.send_message(&self.channel_id, message, "", false);
|
||||
}
|
||||
}
|
||||
|
||||
impl Module for DiscordModule {
|
||||
fn produce_events<'a>(&'a self, sender: Sender<event::Event>) {
|
||||
let discord = Arc::new(Discord::from_bot_token(&self.token[..]).expect("Login failed"));
|
||||
let (mut connection, _) = discord.connect().expect("Connection failed");
|
||||
loop {
|
||||
match connection.recv_event() {
|
||||
Ok(Event::MessageCreate(message)) => {
|
||||
let author = User {
|
||||
name: message.author.name.clone(),
|
||||
sender: Arc::new(DiscordMessageSender {
|
||||
discord: discord.clone(),
|
||||
channel_id: message.channel_id
|
||||
})
|
||||
};
|
||||
|
||||
let channel = Channel {
|
||||
name: String::from("channel"),
|
||||
description: String::from(""),
|
||||
topic: String::from(""),
|
||||
sender: Arc::new(DiscordMessageSender {
|
||||
discord: discord.clone(),
|
||||
channel_id: message.channel_id
|
||||
})
|
||||
};
|
||||
|
||||
sender.send(event::Event::Message { sender: author, content: message.content, channel: Option::Some(channel) });
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(discord::Error::Closed(code, body)) => {
|
||||
println!("Gateway closed on us with code {:?}: {}", code, body);
|
||||
break
|
||||
}
|
||||
Err(err) => println!("Receive error: {:?}", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
src/modules/echo.rs
Normal file
45
src/modules/echo.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use modules::Module;
|
||||
use toml::Table;
|
||||
|
||||
use std::sync::mpsc::Receiver;
|
||||
use event::Event;
|
||||
|
||||
pub struct EchoModule {
|
||||
prefix: String
|
||||
}
|
||||
|
||||
impl EchoModule {
|
||||
pub fn new (configuration: &Table) -> Box<Module> {
|
||||
let prefix = configuration.get("prefix")
|
||||
.and_then(|value| value.as_str())
|
||||
.unwrap_or("!echo ");
|
||||
|
||||
Box::new(EchoModule {
|
||||
prefix: String::from(prefix)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Module for EchoModule {
|
||||
fn consume_events (&self, receiver: Receiver<Event>) {
|
||||
loop {
|
||||
match receiver.recv() {
|
||||
Ok(event) => {
|
||||
match event {
|
||||
Event::Message { content: message, channel, sender } => {
|
||||
if message.starts_with(self.prefix.as_str()) {
|
||||
let substring = &message[self.prefix.chars().count()..];
|
||||
match channel {
|
||||
Some(channel) => channel.send(substring),
|
||||
None => sender.send(substring)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
Err(error) => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
src/modules/hello.rs
Normal file
26
src/modules/hello.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use modules::Module;
|
||||
use toml::Table;
|
||||
|
||||
use Tenquestionmarks;
|
||||
|
||||
pub struct Hello {
|
||||
name: String
|
||||
}
|
||||
|
||||
impl Hello {
|
||||
pub fn new (configuration: &Table) -> Box<Module> {
|
||||
let name = configuration.get("name")
|
||||
.and_then(|value| value.as_str())
|
||||
.unwrap_or("world");
|
||||
|
||||
Box::new(Hello {
|
||||
name: String::from(name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Module for Hello {
|
||||
fn register (&self, tenquestionmarks: &Tenquestionmarks) {
|
||||
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 {}
|
18
src/modules/mod.rs
Normal file
18
src/modules/mod.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
pub mod hello;
|
||||
pub mod lua;
|
||||
pub mod discord;
|
||||
pub mod stdin;
|
||||
pub mod echo;
|
||||
|
||||
pub mod loader;
|
||||
|
||||
use Tenquestionmarks;
|
||||
use event::Event;
|
||||
|
||||
use std::sync::mpsc::{Sender, Receiver};
|
||||
|
||||
pub trait Module : Sync {
|
||||
fn register (&self, tenquestionmarks: &Tenquestionmarks) {}
|
||||
fn consume_events (&self, receiver: Receiver<Event>) {}
|
||||
fn produce_events<'a>(&'a self, sender: Sender<Event>) {}
|
||||
}
|
51
src/modules/stdin.rs
Normal file
51
src/modules/stdin.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use std::io;
|
||||
|
||||
use modules::Module;
|
||||
use toml::Table;
|
||||
|
||||
use User;
|
||||
use MessageSender;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::Sender;
|
||||
use event::Event;
|
||||
|
||||
pub struct StdinModule {}
|
||||
|
||||
pub struct StdinMessageSender {
|
||||
name: String
|
||||
}
|
||||
|
||||
impl MessageSender for StdinMessageSender {
|
||||
fn send_message (&self, message: &str) {
|
||||
println!("send to {:?}: {:?}", self.name, message);
|
||||
}
|
||||
}
|
||||
|
||||
impl StdinModule {
|
||||
pub fn new (configuration: &Table) -> Box<Module> {
|
||||
Box::new(StdinModule {})
|
||||
}
|
||||
}
|
||||
|
||||
impl Module for StdinModule {
|
||||
fn produce_events<'a>(&'a self, sender: Sender<Event>) {
|
||||
let user = User {
|
||||
name: String::from("Dave"),
|
||||
sender: Arc::new(StdinMessageSender {
|
||||
name: String::from("Dave")
|
||||
})
|
||||
};
|
||||
|
||||
loop {
|
||||
let mut input = String::new();
|
||||
match io::stdin().read_line(&mut input) {
|
||||
Ok(n) => {
|
||||
let message = Event::Message { sender: user.clone(), content: input, channel: None };
|
||||
sender.send(message);
|
||||
}
|
||||
Err(error) => println!("error: {}", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user