New filters implementation. "tags" are removed and replaced with an implementation that filters directly on the event, using an object/map instead of strings.

This commit is contained in:
Adrian Malacoda 2017-05-11 01:29:33 -05:00
parent 8cd8756722
commit 25d247f299
3 changed files with 144 additions and 49 deletions

View File

@ -18,50 +18,15 @@ pub enum Event {
pub struct Envelope {
pub from: Option<String>,
pub event: Event,
pub to: Vec<String>,
pub tags: BTreeSet<String>
pub to: Vec<String>
}
impl Envelope {
pub fn new (event: Event) -> Envelope {
let mut tags: BTreeSet<String> = BTreeSet::new();
match &event {
&Event::Message { ref message } => {
tags.insert(String::from("type:message"));
tags.insert(format!("user:{:}", message.author.name));
match message.channel {
Some(ref channel) => {
tags.insert(format!("channel:{:}", channel.name));
},
None => {}
}
},
&Event::SelfJoin { ref channel } => {
tags.insert(String::from("type:selfjoin"));
tags.insert(format!("channel:{:}", channel.name));
},
&Event::SelfQuit { ref channel } => {
tags.insert(String::from("type:selfquit"));
tags.insert(format!("channel:{:}", channel.name));
},
&Event::UserJoin { ref channel, ref user } => {
tags.insert(String::from("type:userjoin"));
tags.insert(format!("channel:{:}", channel.name));
tags.insert(format!("user:{:}", user.name));
},
&Event::UserQuit { ref channel, ref user } => {
tags.insert(String::from("type:userquit"));
tags.insert(format!("channel:{:}", channel.name));
tags.insert(format!("user:{:}", user.name));
}
}
Envelope {
from: None,
event: event,
to: vec![],
tags: tags
to: vec![]
}
}
}

View File

@ -19,6 +19,7 @@ use modules::Module;
use modules::loader::{ModuleLoader, ModuleLoaderError};
mod event;
use event::Event;
use event::Envelope;
use std::sync::Arc;
@ -75,8 +76,7 @@ impl Tenquestionmarks {
Envelope {
from: Some(from.clone()),
event: envelope.event,
to: envelope.to,
tags: envelope.tags
to: envelope.to
}
});
@ -171,20 +171,31 @@ pub trait MessageSender : Sync + Send + std::fmt::Debug {
fn send_message (&self, _: &str) {}
}
trait EventFilter: Sync + Send {
fn accept (&self, envelope: &Envelope) -> bool;
}
struct Subscription {
pub module: Module,
pub name: String,
pub filters: BTreeSet<String>
pub filters: Vec<Box<EventFilter>>
}
impl Subscription {
pub fn new (name: String, module: Module) -> Subscription {
let filters: BTreeSet<String> = module.config.get("filters")
let filters: Vec<Box<EventFilter>> = module.config.get("filters")
.and_then(|value| value.as_slice())
.map(|value| value.to_vec())
.unwrap_or(vec![])
.into_iter()
.map(|value| { String::from(value.as_str().unwrap()) })
.map(|value| {
match value.as_table() {
Some(table) => Some(Box::new(AttributeEventFilter::new(table)) as Box<EventFilter>),
None => None
}
})
.filter(|possible_filter| possible_filter.is_some())
.map(|possible_filter| possible_filter.unwrap())
.collect();
Subscription {
@ -208,7 +219,13 @@ impl Subscription {
);
return false;
}
else if !(self.filters.is_empty() || self.filters.intersection(&envelope.tags).count() > 0) {
else if !self.filters.is_empty() {
for filter in &self.filters {
if filter.accept(envelope) {
return true;
}
}
debug!(
"Refusing to transmit envelope from {:?} to {:?} since envelope was filtered out",
envelope.from,
@ -220,3 +237,107 @@ impl Subscription {
true
}
}
struct AttributeEventFilter {
// Attributes that can be filtered out
event_type: Option<String>,
username: Option<String>,
channel: Option<String>,
message: Option<String>
}
impl AttributeEventFilter {
pub fn new (attributes: &Table) -> AttributeEventFilter {
AttributeEventFilter {
event_type: attributes.get("type").and_then(|value| value.as_str()).map(|value| String::from(value)),
message: attributes.get("message").and_then(|value| value.as_str()).map(|value| String::from(value)),
username: attributes.get("username").and_then(|value| value.as_str()).map(|value| String::from(value)),
channel: attributes.get("channel").and_then(|value| value.as_str()).map(|value| String::from(value)),
}
}
}
impl EventFilter for AttributeEventFilter {
fn accept (&self, envelope: &Envelope) -> bool {
let mut result = true;
match &envelope.event {
&Event::Message { ref message } => {
match self.event_type {
Some(ref event_type) => result = result && event_type == "message",
None => {}
}
match self.channel {
Some(ref channel_name) => {
match message.channel {
Some(ref channel) => result = result && channel_name == &channel.name,
None => result = false
}
},
None => {}
}
match self.username {
Some(ref username) => result = result && &message.author.name == username,
None => {}
}
},
&Event::SelfJoin { ref channel } => {
match self.event_type {
Some(ref event_type) => result = result && event_type == "selfjoin",
None => {}
}
match self.channel {
Some(ref channel_name) => result = result && channel_name == &channel.name,
None => {}
}
},
&Event::SelfQuit { ref channel } => {
match self.event_type {
Some(ref event_type) => result = result && event_type == "selfquit",
None => {}
}
match self.channel {
Some(ref channel_name) => result = result && channel_name == &channel.name,
None => {}
}
},
&Event::UserJoin { ref channel, ref user } => {
match self.event_type {
Some(ref event_type) => result = result && event_type == "userjoin",
None => {}
}
match self.channel {
Some(ref channel_name) => result = result && channel_name == &channel.name,
None => {}
}
match self.username {
Some(ref username) => result = result && &user.name == username,
None => {}
}
},
&Event::UserQuit { ref channel, ref user } => {
match self.event_type {
Some(ref event_type) => result = result && event_type == "userquit",
None => {}
}
match self.channel {
Some(ref channel_name) => result = result && channel_name == &channel.name,
None => {}
}
match self.username {
Some(ref username) => result = result && &user.name == username,
None => {}
}
}
}
result
}
}

View File

@ -73,7 +73,16 @@ end
"""
foo = "bar"
[lua2]
type = "lua"
filters = [{ username = "David" }]
code = """
function on_message (message, reply)
reply("Lua2 says: " .. message)
end
"""
[autolink]
[logger]
filters = ["user:Dave"]
filters = [{ username = "Dave" }]