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"
|
hlua = "0.3"
|
||||||
discord = "0.7.0"
|
discord = "0.7.0"
|
||||||
toml = "0.2.1"
|
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 toml;
|
||||||
|
extern crate crossbeam;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
mod plugins;
|
mod plugins;
|
||||||
use plugins::Plugin;
|
use plugins::Plugin;
|
||||||
use plugins::loader::PluginLoader;
|
use plugins::loader::{PluginLoader, PluginLoaderError};
|
||||||
use plugins::loader::PluginLoaderError;
|
|
||||||
|
mod event;
|
||||||
|
use event::Event;
|
||||||
|
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::sync::mpsc::{Sender, Receiver};
|
||||||
|
|
||||||
pub struct Tenquestionmarks {
|
pub struct Tenquestionmarks {
|
||||||
plugins: BTreeMap<String, Box<Plugin>>
|
plugins: BTreeMap<String, Box<Plugin>>
|
||||||
@ -14,9 +20,15 @@ pub struct Tenquestionmarks {
|
|||||||
|
|
||||||
impl Tenquestionmarks {
|
impl Tenquestionmarks {
|
||||||
pub fn with_plugins (plugins: BTreeMap<String, Box<Plugin>>) -> Tenquestionmarks {
|
pub fn with_plugins (plugins: BTreeMap<String, Box<Plugin>>) -> Tenquestionmarks {
|
||||||
Tenquestionmarks {
|
let tqm = Tenquestionmarks {
|
||||||
plugins: plugins
|
plugins: plugins
|
||||||
|
};
|
||||||
|
|
||||||
|
for (key, plugin) in &tqm.plugins {
|
||||||
|
plugin.register(&tqm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tqm
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_configuration (configuration: Table) -> Result<Tenquestionmarks, PluginLoaderError> {
|
pub fn from_configuration (configuration: Table) -> Result<Tenquestionmarks, PluginLoaderError> {
|
||||||
@ -24,20 +36,58 @@ impl Tenquestionmarks {
|
|||||||
let plugins = loader.load_from_configuration(configuration)?;
|
let plugins = loader.load_from_configuration(configuration)?;
|
||||||
Result::Ok(Tenquestionmarks::with_plugins(plugins))
|
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 {
|
pub struct Channel {
|
||||||
name: String,
|
name: String,
|
||||||
description: String,
|
description: String,
|
||||||
topic: String
|
topic: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
name: String
|
name: String
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Message {
|
|
||||||
sender: String,
|
|
||||||
target: String,
|
|
||||||
content: String
|
|
||||||
}
|
|
||||||
|
@ -20,7 +20,10 @@ fn main () {
|
|||||||
Some(configuration) => {
|
Some(configuration) => {
|
||||||
println!("Loaded configuration from: {}", configFileName);
|
println!("Loaded configuration from: {}", configFileName);
|
||||||
match Tenquestionmarks::from_configuration(configuration) {
|
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)
|
Err(e) => println!("Failed to initialize tenquestionmarks: {:?}", e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use plugins::Plugin;
|
use plugins::Plugin;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
|
use Tenquestionmarks;
|
||||||
|
|
||||||
pub struct DiscordPlugin {
|
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 plugins::Plugin;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
|
use Tenquestionmarks;
|
||||||
|
|
||||||
pub struct Hello {
|
pub struct Hello {
|
||||||
name: String
|
name: String
|
||||||
}
|
}
|
||||||
@ -11,7 +13,6 @@ impl Hello {
|
|||||||
.and_then(|value| value.as_str())
|
.and_then(|value| value.as_str())
|
||||||
.unwrap_or("world");
|
.unwrap_or("world");
|
||||||
|
|
||||||
println!("Hello, {}!", name);
|
|
||||||
Box::new(Hello {
|
Box::new(Hello {
|
||||||
name: String::from(name)
|
name: String::from(name)
|
||||||
})
|
})
|
||||||
@ -19,5 +20,7 @@ impl Hello {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Plugin for 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::hello::Hello;
|
||||||
use plugins::discord::DiscordPlugin;
|
use plugins::discord::DiscordPlugin;
|
||||||
use plugins::lua::LuaPlugin;
|
use plugins::lua::LuaPlugin;
|
||||||
|
use plugins::stdin::StdinPlugin;
|
||||||
|
use plugins::echo::EchoPlugin;
|
||||||
|
|
||||||
pub struct PluginLoader {
|
pub struct PluginLoader {
|
||||||
types: BTreeMap<&'static str, fn(&Table) -> Box<Plugin>>
|
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("hello", Hello::new as fn(&Table) -> Box<Plugin>);
|
||||||
types.insert("discord", DiscordPlugin::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("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 {
|
PluginLoader {
|
||||||
types: types
|
types: types
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use plugins::Plugin;
|
use plugins::Plugin;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
|
use Tenquestionmarks;
|
||||||
|
|
||||||
pub struct LuaPlugin {
|
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 hello;
|
||||||
pub mod lua;
|
pub mod lua;
|
||||||
pub mod discord;
|
pub mod discord;
|
||||||
|
pub mod stdin;
|
||||||
|
pub mod echo;
|
||||||
|
|
||||||
pub mod loader;
|
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]
|
[discord]
|
||||||
channel = "#testchannelpleaseignore"
|
channel = "#testchannelpleaseignore"
|
||||||
|
|
||||||
|
[stdin]
|
||||||
|
|
||||||
|
[echo]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user