Flesh out plugins event handling, add example stdin plugin (event producer) and echo plugin (event consumer). Next step: fleshing out user/channel structs
This commit is contained in:
parent
a31b060dd3
commit
26a6b77632
@ -7,3 +7,4 @@ authors=["Adrian Malacoda <adrian.malacoda@monarch-pass.net>"]
|
||||
hlua = "0.3"
|
||||
discord = "0.7.0"
|
||||
toml = "0.2.1"
|
||||
crossbeam = "0.2"
|
||||
|
8
src/event/mod.rs
Normal file
8
src/event/mod.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use {Channel, User};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Event<'a> {
|
||||
Message { sender: &'a User, channel: Option<&'a Channel>, content: String },
|
||||
Join { channel: &'a Channel },
|
||||
Quit { channel: &'a Channel }
|
||||
}
|
68
src/lib.rs
68
src/lib.rs
@ -1,12 +1,18 @@
|
||||
extern crate toml;
|
||||
extern crate crossbeam;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use toml::Table;
|
||||
|
||||
mod plugins;
|
||||
use plugins::Plugin;
|
||||
use plugins::loader::PluginLoader;
|
||||
use plugins::loader::PluginLoaderError;
|
||||
use plugins::loader::{PluginLoader, PluginLoaderError};
|
||||
|
||||
mod event;
|
||||
use event::Event;
|
||||
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::{Sender, Receiver};
|
||||
|
||||
pub struct Tenquestionmarks {
|
||||
plugins: BTreeMap<String, Box<Plugin>>
|
||||
@ -14,9 +20,15 @@ pub struct Tenquestionmarks {
|
||||
|
||||
impl Tenquestionmarks {
|
||||
pub fn with_plugins (plugins: BTreeMap<String, Box<Plugin>>) -> Tenquestionmarks {
|
||||
Tenquestionmarks {
|
||||
let tqm = Tenquestionmarks {
|
||||
plugins: plugins
|
||||
};
|
||||
|
||||
for (key, plugin) in &tqm.plugins {
|
||||
plugin.register(&tqm);
|
||||
}
|
||||
|
||||
tqm
|
||||
}
|
||||
|
||||
pub fn from_configuration (configuration: Table) -> Result<Tenquestionmarks, PluginLoaderError> {
|
||||
@ -24,20 +36,58 @@ impl Tenquestionmarks {
|
||||
let plugins = loader.load_from_configuration(configuration)?;
|
||||
Result::Ok(Tenquestionmarks::with_plugins(plugins))
|
||||
}
|
||||
|
||||
pub fn run (&self) {
|
||||
crossbeam::scope(|scope| {
|
||||
// Our event channel.
|
||||
// Plugins push events to tenquestionmarks using this channel.
|
||||
let (ref sender, ref receiver) = mpsc::channel();
|
||||
|
||||
// Plugin event channels.
|
||||
// tenquestionmarks propagates all events to each plugin through these
|
||||
// channels.
|
||||
let senders: Vec<Sender<Event>> = self.plugins.values().map(|plugin| {
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
scope.spawn(move || {
|
||||
loop {
|
||||
match receiver.recv() {
|
||||
Ok(event) => { plugin.on_event(event) }
|
||||
Err(error) => { println!("{:?}", error); }
|
||||
}
|
||||
}
|
||||
});
|
||||
sender
|
||||
}).collect();
|
||||
|
||||
// Plugin main threads.
|
||||
for plugin in self.plugins.values() {
|
||||
let plugin_sender = sender.clone();
|
||||
scope.spawn(move || plugin.run(plugin_sender));
|
||||
}
|
||||
|
||||
// tenquestionmarks main event loop.
|
||||
loop {
|
||||
match receiver.recv() {
|
||||
Ok(event) => {
|
||||
for sender in &senders {
|
||||
sender.send(event.clone());
|
||||
}
|
||||
},
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Channel {
|
||||
name: String,
|
||||
description: String,
|
||||
topic: String
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct User {
|
||||
name: String
|
||||
}
|
||||
|
||||
pub struct Message {
|
||||
sender: String,
|
||||
target: String,
|
||||
content: String
|
||||
}
|
||||
|
@ -20,7 +20,10 @@ fn main () {
|
||||
Some(configuration) => {
|
||||
println!("Loaded configuration from: {}", configFileName);
|
||||
match Tenquestionmarks::from_configuration(configuration) {
|
||||
Ok(tqm) => println!("loaded tenquestionmarks"),
|
||||
Ok(tqm) => {
|
||||
println!("tenquestionmarks initialized successfully");
|
||||
tqm.run();
|
||||
},
|
||||
Err(e) => println!("Failed to initialize tenquestionmarks: {:?}", e)
|
||||
}
|
||||
},
|
||||
|
@ -1,6 +1,8 @@
|
||||
use plugins::Plugin;
|
||||
use toml::Table;
|
||||
|
||||
use Tenquestionmarks;
|
||||
|
||||
pub struct DiscordPlugin {
|
||||
|
||||
}
|
||||
@ -16,6 +18,4 @@ impl DiscordPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for DiscordPlugin {
|
||||
|
||||
}
|
||||
impl Plugin for DiscordPlugin {}
|
||||
|
34
src/plugins/echo.rs
Normal file
34
src/plugins/echo.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use plugins::Plugin;
|
||||
use toml::Table;
|
||||
|
||||
use event::Event;
|
||||
|
||||
pub struct EchoPlugin {
|
||||
prefix: String
|
||||
}
|
||||
|
||||
impl EchoPlugin {
|
||||
pub fn new (configuration: &Table) -> Box<Plugin> {
|
||||
let prefix = configuration.get("prefix")
|
||||
.and_then(|value| value.as_str())
|
||||
.unwrap_or("!echo ");
|
||||
|
||||
Box::new(EchoPlugin {
|
||||
prefix: String::from(prefix)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for EchoPlugin {
|
||||
fn on_event (&self, event: Event) {
|
||||
match event {
|
||||
Event::Message { content: message, channel: channel, sender: sender } => {
|
||||
if message.starts_with(self.prefix.as_str()) {
|
||||
let substring = String::from(&message[self.prefix.chars().count()..]);
|
||||
println!("Echo: {:?}", substring);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
use plugins::Plugin;
|
||||
use toml::Table;
|
||||
|
||||
use Tenquestionmarks;
|
||||
|
||||
pub struct Hello {
|
||||
name: String
|
||||
}
|
||||
@ -11,7 +13,6 @@ impl Hello {
|
||||
.and_then(|value| value.as_str())
|
||||
.unwrap_or("world");
|
||||
|
||||
println!("Hello, {}!", name);
|
||||
Box::new(Hello {
|
||||
name: String::from(name)
|
||||
})
|
||||
@ -19,5 +20,7 @@ impl Hello {
|
||||
}
|
||||
|
||||
impl Plugin for Hello {
|
||||
|
||||
fn register (&self, tenquestionmarks: &Tenquestionmarks) {
|
||||
println!("Hello, {}!", self.name);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ 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>>
|
||||
@ -19,6 +21,8 @@ impl PluginLoader {
|
||||
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
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
use plugins::Plugin;
|
||||
use toml::Table;
|
||||
|
||||
use Tenquestionmarks;
|
||||
|
||||
pub struct LuaPlugin {
|
||||
|
||||
}
|
||||
@ -11,6 +13,4 @@ impl LuaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for LuaPlugin {
|
||||
|
||||
}
|
||||
impl Plugin for LuaPlugin {}
|
||||
|
@ -6,9 +6,18 @@ use toml::Table;
|
||||
pub mod hello;
|
||||
pub mod lua;
|
||||
pub mod discord;
|
||||
pub mod stdin;
|
||||
pub mod echo;
|
||||
|
||||
pub mod loader;
|
||||
|
||||
pub trait Plugin {
|
||||
use Tenquestionmarks;
|
||||
use event::Event;
|
||||
|
||||
use std::sync::mpsc::{Sender, Receiver};
|
||||
|
||||
pub trait Plugin : Sync {
|
||||
fn register (&self, tenquestionmarks: &Tenquestionmarks) {}
|
||||
fn on_event (&self, event: Event) {}
|
||||
fn run (&self, sender: Sender<Event>) {}
|
||||
}
|
||||
|
45
src/plugins/stdin.rs
Normal file
45
src/plugins/stdin.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use std::io;
|
||||
|
||||
use plugins::Plugin;
|
||||
use toml::Table;
|
||||
|
||||
use Tenquestionmarks;
|
||||
use User;
|
||||
|
||||
use std::sync::mpsc::Sender;
|
||||
use event::Event;
|
||||
|
||||
pub struct StdinPlugin {
|
||||
user: User
|
||||
}
|
||||
|
||||
impl StdinPlugin {
|
||||
pub fn new (configuration: &Table) -> Box<Plugin> {
|
||||
Box::new(StdinPlugin {
|
||||
user: User {
|
||||
name: String::from("Dave")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for StdinPlugin {
|
||||
fn register (&self, tenquestionmarks: &Tenquestionmarks) {
|
||||
|
||||
}
|
||||
|
||||
fn run (&self, sender: Sender<Event>) {
|
||||
let user = &self.user;
|
||||
|
||||
loop {
|
||||
let mut input = String::new();
|
||||
match io::stdin().read_line(&mut input) {
|
||||
Ok(n) => {
|
||||
let message = Event::Message { sender: user, content: input, channel: None };
|
||||
sender.send(message);
|
||||
}
|
||||
Err(error) => println!("error: {}", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,3 +10,7 @@ name = "Fred"
|
||||
|
||||
[discord]
|
||||
channel = "#testchannelpleaseignore"
|
||||
|
||||
[stdin]
|
||||
|
||||
[echo]
|
||||
|
Loading…
x
Reference in New Issue
Block a user