rearchitect event transmission so that the parents/children of each module are explicitly specified and we establish the linkages between them
This commit is contained in:
parent
3614c7eb5d
commit
fcc86a671e
@ -14,6 +14,7 @@ env_logger = "0.5.3"
|
||||
transformable_channels = "0.1.1"
|
||||
time = "0.1"
|
||||
regex = "0.2"
|
||||
multimap = "0.4.0"
|
||||
pvn = { git = "http://gitlab.monarch-pass.net/malacoda/pvn.git" }
|
||||
echobox = { git = "http://gitlab.monarch-pass.net/malacoda/echobox.git" }
|
||||
stc = { git = "http://gitlab.monarch-pass.net/malacoda/stc.git" }
|
||||
|
@ -1,8 +1,5 @@
|
||||
use {Message, Channel, User};
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::btree_set::BTreeSet;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Event {
|
||||
Message { message: Message }, // A user sends a message
|
||||
@ -18,15 +15,13 @@ pub enum Event {
|
||||
pub struct Envelope {
|
||||
pub from: Option<String>,
|
||||
pub event: Event,
|
||||
pub to: Vec<String>
|
||||
}
|
||||
|
||||
impl Envelope {
|
||||
pub fn new (event: Event) -> Envelope {
|
||||
Envelope {
|
||||
from: None,
|
||||
event: event,
|
||||
to: vec![]
|
||||
event: event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
72
src/lib.rs
72
src/lib.rs
@ -7,6 +7,7 @@ extern crate echobox;
|
||||
extern crate transformable_channels;
|
||||
extern crate stc;
|
||||
extern crate regex;
|
||||
extern crate multimap;
|
||||
|
||||
#[macro_use]
|
||||
extern crate hlua;
|
||||
@ -27,6 +28,7 @@ use std::sync::mpsc;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use transformable_channels::mpsc::TransformableSender;
|
||||
use multimap::MultiMap;
|
||||
|
||||
mod helpers;
|
||||
|
||||
@ -34,18 +36,31 @@ mod helpers;
|
||||
extern crate log;
|
||||
|
||||
pub struct Tenquestionmarks {
|
||||
subscriptions: BTreeMap<String, Subscription>
|
||||
modules: BTreeMap<String, Module>,
|
||||
subscriptions: MultiMap<String, Subscription>
|
||||
}
|
||||
|
||||
impl Tenquestionmarks {
|
||||
pub fn with_modules (modules: BTreeMap<String, Module>) -> Tenquestionmarks {
|
||||
let tqm = Tenquestionmarks {
|
||||
subscriptions: modules.into_iter().map(|(key, module)| {
|
||||
(key.clone(), Subscription::new(key.clone(), module))
|
||||
}).collect()
|
||||
};
|
||||
let mut subscriptions = MultiMap::new();
|
||||
for (name, module) in modules.iter() {
|
||||
for parent in module.parents() {
|
||||
info!("{:?} registered as parent of {:?}", parent, name);
|
||||
subscriptions.insert(parent, Subscription::new(name.to_owned(), &module));
|
||||
}
|
||||
|
||||
tqm
|
||||
for child_name in module.children() {
|
||||
if let Some(ref child) = modules.get(&child_name) {
|
||||
info!("{:?} registered as child of {:?}", child_name, name);
|
||||
subscriptions.insert(name.clone(), Subscription::new(child_name.to_owned(), &child));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tenquestionmarks {
|
||||
modules: modules,
|
||||
subscriptions: subscriptions
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_configuration (configuration: Table) -> Result<Tenquestionmarks, ModuleLoaderError> {
|
||||
@ -65,20 +80,19 @@ impl Tenquestionmarks {
|
||||
// into all other Modules.
|
||||
// tenquestionmarks propagates all events to each Module through these
|
||||
// channels.
|
||||
let module_senders: BTreeMap<&str, Sender<Arc<Envelope>>> = self.subscriptions.iter().map(|(key, subscription)| {
|
||||
let module_senders: BTreeMap<&str, Sender<Arc<Envelope>>> = self.modules.iter().map(|(key, module)| {
|
||||
let from = key.clone();
|
||||
let main_sender_mapped = main_sender.map(move |envelope: Envelope| {
|
||||
Envelope {
|
||||
from: Some(from.clone()),
|
||||
event: envelope.event,
|
||||
to: envelope.to
|
||||
event: envelope.event
|
||||
}
|
||||
});
|
||||
|
||||
let (module_sender, module_receiver) = mpsc::channel();
|
||||
info!("Spawning thread for \"{}\"", key);
|
||||
scope.spawn(move || {
|
||||
subscription.module.run(Box::new(main_sender_mapped), module_receiver);
|
||||
module.run(Box::new(main_sender_mapped), module_receiver);
|
||||
info!("Thread for \"{}\" is exiting", key);
|
||||
});
|
||||
(&key[..], module_sender)
|
||||
@ -98,16 +112,17 @@ impl Tenquestionmarks {
|
||||
* names the target module.
|
||||
*/
|
||||
let arc_envelope = Arc::new(envelope);
|
||||
for (key, sender) in &module_senders {
|
||||
let from_this = String::from(*key);
|
||||
if let Some(subscription) = self.subscriptions.get::<String>(&from_this) {
|
||||
if subscription.can_handle_event(&arc_envelope) {
|
||||
if let Err(err) = sender.send(arc_envelope.clone()) {
|
||||
debug!("Failed to dispatch event to module \"{}\": {:?}", key, err);
|
||||
if let Some(ref from) = arc_envelope.from {
|
||||
if let Some(subscriptions) = self.subscriptions.get_vec(&**from) {
|
||||
for subscription in subscriptions {
|
||||
if subscription.can_handle_event(&arc_envelope) {
|
||||
if let Some(sender) = module_senders.get(&*subscription.name) {
|
||||
if let Err(err) = sender.send(arc_envelope.clone()) {
|
||||
debug!("Failed to dispatch event to module \"{}\": {:?}", subscription.name, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!("Failed to dispatch event to module \"{}\": No such module found!", key);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -169,13 +184,12 @@ trait EventFilter: Sync + Send {
|
||||
}
|
||||
|
||||
struct Subscription {
|
||||
pub module: Module,
|
||||
pub name: String,
|
||||
pub filters: Vec<Box<EventFilter>>
|
||||
}
|
||||
|
||||
impl Subscription {
|
||||
pub fn new (name: String, module: Module) -> Subscription {
|
||||
pub fn new (name: String, module: &Module) -> Subscription {
|
||||
let filters: Vec<Box<EventFilter>> = module.config.get("filters")
|
||||
.and_then(|value| value.as_array())
|
||||
.map(|value| value.to_vec())
|
||||
@ -192,27 +206,13 @@ impl Subscription {
|
||||
.collect();
|
||||
|
||||
Subscription {
|
||||
module: module,
|
||||
name: name,
|
||||
filters: filters
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_handle_event (&self, envelope: &Envelope) -> bool {
|
||||
if Some(&self.name) == envelope.from.as_ref() {
|
||||
debug!("Refusing to transmit event to its originator ({:?})", self.name);
|
||||
return false;
|
||||
}
|
||||
else if !(envelope.to.is_empty() || !envelope.to.contains(&self.name)) {
|
||||
debug!(
|
||||
"Refusing to transmit envelope from {:?} to {:?} since it is not on the list of allowed recipients ({:?})",
|
||||
envelope.from,
|
||||
self.name,
|
||||
envelope.to
|
||||
);
|
||||
return false;
|
||||
}
|
||||
else if !self.filters.is_empty() {
|
||||
if !self.filters.is_empty() {
|
||||
for filter in &self.filters {
|
||||
if filter.accept(envelope) {
|
||||
return true;
|
||||
|
@ -10,7 +10,6 @@ pub mod logger;
|
||||
|
||||
pub mod loader;
|
||||
|
||||
use Tenquestionmarks;
|
||||
use event::Envelope;
|
||||
|
||||
use std::sync::Arc;
|
||||
@ -22,13 +21,37 @@ use toml::value::Table;
|
||||
pub struct Module {
|
||||
event_loop: Box<EventLoop>,
|
||||
module_type: String,
|
||||
pub config: Table
|
||||
pub config: Table,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
pub fn run (&self, sender: Box<ExtSender<Envelope>>, receiver: Receiver<Arc<Envelope>>) {
|
||||
self.event_loop.run(sender, receiver);
|
||||
}
|
||||
|
||||
pub fn parents (&self) -> Vec<String> {
|
||||
self.config.get("parents")
|
||||
.and_then(|value| value.as_array())
|
||||
.map(|value| value.to_vec())
|
||||
.unwrap_or(vec![])
|
||||
.iter()
|
||||
.map(|value| value.as_str())
|
||||
.filter(|value| value.is_some())
|
||||
.map(|value| value.unwrap().to_owned())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn children (&self) -> Vec<String> {
|
||||
self.config.get("children")
|
||||
.and_then(|value| value.as_array())
|
||||
.map(|value| value.to_vec())
|
||||
.unwrap_or(vec![])
|
||||
.iter()
|
||||
.map(|value| value.as_str())
|
||||
.filter(|value| value.is_some())
|
||||
.map(|value| value.unwrap().to_owned())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EventLoop : Sync {
|
||||
|
@ -7,10 +7,12 @@ token = "your token here"
|
||||
[stdin]
|
||||
|
||||
[echo]
|
||||
parents = ["stdin", "discord"]
|
||||
prefix = "?echo"
|
||||
|
||||
[no]
|
||||
type = "random"
|
||||
parents = ["stdin", "discord"]
|
||||
prefix = "?no"
|
||||
responses = [
|
||||
"https://www.youtube.com/watch?v=WWaLxFIVX1s", # Darth Vader
|
||||
@ -36,6 +38,7 @@ responses = [
|
||||
|
||||
[yes]
|
||||
type = "random"
|
||||
parents = ["stdin", "discord"]
|
||||
prefix = "?yes"
|
||||
responses = [
|
||||
"https://www.youtube.com/watch?v=JPVaDaynNKM", # Captain Falcon
|
||||
@ -58,14 +61,18 @@ responses = [
|
||||
|
||||
[chk]
|
||||
type = "random"
|
||||
parents = ["stdin", "discord"]
|
||||
prefix = "?chk"
|
||||
responses = ["ack"]
|
||||
|
||||
[pvn]
|
||||
parents = ["stdin", "discord"]
|
||||
|
||||
[echobox]
|
||||
parents = ["stdin", "discord"]
|
||||
|
||||
[lua]
|
||||
parents = ["stdin", "discord"]
|
||||
code = """
|
||||
function on_message (message, reply)
|
||||
reply("Lua says: " .. message)
|
||||
@ -75,6 +82,7 @@ foo = "bar"
|
||||
|
||||
[lua2]
|
||||
type = "lua"
|
||||
parents = ["stdin", "discord"]
|
||||
filters = [{ username = "David" }]
|
||||
code = """
|
||||
function on_message (message, reply)
|
||||
@ -83,6 +91,8 @@ end
|
||||
"""
|
||||
|
||||
[autolink]
|
||||
parents = ["stdin", "discord"]
|
||||
|
||||
[logger]
|
||||
parents = ["stdin", "discord"]
|
||||
filters = [{ username = "Dave" }, { username = "Kevin" }]
|
||||
|
Loading…
x
Reference in New Issue
Block a user