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