Compare commits

..

13 Commits

Author SHA1 Message Date
496ba89d94 Temporarily disable modules that no longer work. 2023-03-13 00:21:50 -05:00
Adrian Malacoda
ae9945403f add cat and dog modules 2018-05-12 02:11:23 -05:00
Adrian Malacoda
3a06d98247 increment version 2018-05-12 01:37:20 -05:00
Adrian Malacoda
9052a3b26b add method to get vec from config 2018-05-12 00:41:04 -05:00
Adrian Malacoda
4bfe6e2aec initial attempt at limiting to guilds 2018-05-12 00:37:03 -05:00
Adrian Malacoda
a698450c1e add ability to specify a list of guilds for discord module. Intent is to be able to filter events to specific guilds. 2018-05-12 00:28:39 -05:00
Adrian Malacoda
0d4718c3f3 add a helper trait that extends Table for more convenient value retrieval 2018-05-12 00:11:44 -05:00
Adrian Malacoda
cbf1688bdd make autolink pattern configurable 2018-05-11 23:57:22 -05:00
Adrian Malacoda
138e4edc08 add configuration option for autolink searcher 2018-05-11 22:04:45 -05:00
Adrian Malacoda
5fb167a8d0 add $sender variable to random response module 2018-05-06 04:19:54 -05:00
Adrian Malacoda
9271c39ce2 update irc module 2018-05-06 04:03:37 -05:00
Adrian Malacoda
4e6d648d18 fix autolink to use scryfall data type 2018-05-06 03:55:14 -05:00
Adrian Malacoda
1c870b58e4 update dependencies 2018-05-06 03:44:43 -05:00
26 changed files with 299 additions and 89 deletions

View File

@ -1,11 +1,12 @@
[package] [package]
name="tenquestionmarks" name="tenquestionmarks"
version="0.0.3" version="0.0.4"
authors=["Adrian Malacoda <adrian.malacoda@monarch-pass.net>"] authors=["Adrian Malacoda <adrian.malacoda@monarch-pass.net>"]
[dependencies] [dependencies]
hlua = "0.4.1" hlua = "0.4.1"
discord = "0.8.0" #discord = { git = "https://github.com/tinaun/discord-rs", branch = "async_internals" }
#discord = "0.8.1"
toml = "0.4.5" toml = "0.4.5"
crossbeam = "0.3.2" crossbeam = "0.3.2"
rand = "0.4.2" rand = "0.4.2"
@ -13,11 +14,13 @@ log = "0.4.1"
env_logger = "0.5.3" 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 = "^1"
multimap = "0.4.0" multimap = "0.4.0"
notify = "4.0.0" notify = "4.0.0"
irc = "0.11.8" # latest version which supports old openssl version (required by discord) irc = "0.13.5"
thread_local = "0.3" thread_local = "0.3"
pvn = { git = "http://gitlab.monarch-pass.net/malacoda/pvn.git" } pvn = { git = "https://forge.ds8.zone/beyond/pvn.git" }
echobox = { git = "http://gitlab.monarch-pass.net/malacoda/echobox.git" } echobox = { git = "https://forge.ds8.zone/beyond/echobox.git" }
stc = { git = "http://gitlab.monarch-pass.net/malacoda/stc.git" } stc = { git = "https://forge.ds8.zone/beyond/stc.git" }
#i-can-has-cat = { git = "https://forge.ds8.zone/beyond/i-can-has-cat.git" }
#wow-such-doge = { git = "https://forge.ds8.zone/beyond/wow-such-doge.git" }

0
README.md Normal file → Executable file
View File

0
TODO.md Normal file → Executable file
View File

0
lua/dailies.lua Normal file → Executable file
View File

0
src/event/filter.rs Normal file → Executable file
View File

0
src/event/mod.rs Normal file → Executable file
View File

0
src/helpers/command.rs Normal file → Executable file
View File

18
src/helpers/config.rs Executable file
View File

@ -0,0 +1,18 @@
use toml;
use toml::value::Table;
pub trait Config {
fn get_string (&self, key: &str) -> Option<&str>;
fn get_vec (&self, key: &str) -> Option<Vec<toml::Value>>;
}
impl Config for Table {
fn get_string (&self, key: &str) -> Option<&str> {
self.get(key).and_then(|value| value.as_str())
}
fn get_vec (&self, key: &str) -> Option<Vec<toml::Value>> {
self.get(key).and_then(|value| value.as_array())
.map(|value| value.to_vec())
}
}

1
src/helpers/mod.rs Normal file → Executable file
View File

@ -1 +1,2 @@
pub mod command; pub mod command;
pub mod config;

4
src/lib.rs Normal file → Executable file
View File

@ -1,6 +1,6 @@
extern crate toml; extern crate toml;
extern crate crossbeam; extern crate crossbeam;
extern crate discord; //extern crate discord;
extern crate rand; extern crate rand;
extern crate pvn; extern crate pvn;
extern crate echobox; extern crate echobox;
@ -10,6 +10,8 @@ extern crate regex;
extern crate multimap; extern crate multimap;
extern crate irc; extern crate irc;
extern crate thread_local; extern crate thread_local;
//extern crate i_can_has_cat;
//extern crate wow_such_doge;
#[macro_use] #[macro_use]
extern crate hlua; extern crate hlua;

0
src/main.rs Normal file → Executable file
View File

75
src/modules/autolink.rs Normal file → Executable file
View File

@ -17,30 +17,73 @@ use stc::searchers::mediawiki::MediawikiSearcher;
use regex::Regex; use regex::Regex;
use std::collections::BTreeMap; use std::collections::BTreeMap;
pub struct AutolinkModule {} const DEFAULT_PATTERN: &str = r"\[\[([^\[\]]*)\]\]";
pub struct AutolinkModule {
searcher_config: Table,
pattern: Regex
}
impl AutolinkModule { impl AutolinkModule {
pub fn new (_: &Table, _: &Table) -> Box<EventLoop> { pub fn new (_: &Table, configuration: &Table) -> Box<EventLoop> {
Box::new(AutolinkModule {}) let searcher_config = configuration.get("searchers").expect("No configuration for searcher found")
.as_table().expect("Searcher config must be a table");
let pattern = configuration.get("pattern")
.and_then(|value| value.as_str())
.or(Some(DEFAULT_PATTERN))
.map(String::from)
.and_then(|value| Regex::new(&value).ok())
.expect("Invalid value for pattern");
Box::new(AutolinkModule {
searcher_config: searcher_config.clone(),
pattern: pattern
})
} }
} }
fn create_searcher (configuration: &Table) -> AggregateSearcher {
let mut searchers = AggregateSearcher::new();
for (prefix, searcher_config) in configuration.iter() {
if let Some(searcher_type) = searcher_config.get("type") {
match searcher_type.as_str() {
Some("mtg") => searchers.add_searcher(prefix, Box::new(MtgSearcher::new())),
Some("ygo") => searchers.add_searcher(prefix, Box::new(YugiohSearcher::new())),
Some("wiki") => {
if let Some(url) = searcher_config.get("url") {
match url.as_str() {
Some(url) => searchers.add_searcher(prefix, Box::new(MediawikiSearcher::new(url.to_owned()))),
None => warn!("Missing url for wiki searcher {}", prefix)
}
}
},
Some(unknown_type) => info!("Unrecognized searcher type {} for {}", unknown_type, prefix),
None => warn!("No searcher type given for {}", prefix)
}
}
}
searchers
}
fn print_mtg_card (card: &MtgCard, message: &Message) { fn print_mtg_card (card: &MtgCard, message: &Message) {
message.reply(&format!("{}", card.image_url)); if let Some(ref image_uri) = card.image_uris.get("normal") {
message.reply(&format!("{}", image_uri));
}
if let Some(ref cost) = card.cost { if let Some(ref cost) = card.mana_cost {
message.reply(&format!("**{}** (**{}**)", card.name, cost)); message.reply(&format!("**{}** (**{}**)", card.name, cost));
} else { } else {
message.reply(&format!("**{}**", card.name)); message.reply(&format!("**{}**", card.name));
} }
message.reply(&format!("**{}**", card.typeline)); message.reply(&format!("**{}**", card.type_line));
if let Some(ref rules) = card.rules { if let Some(ref rules) = card.oracle_text {
message.reply(&format!("{}", rules)); message.reply(&format!("{}", rules));
} }
if let Some(ref flavor) = card.flavor { if let Some(ref flavor) = card.flavor_text {
message.reply(&format!("*{}*", flavor)); message.reply(&format!("*{}*", flavor));
} }
@ -79,17 +122,7 @@ fn print_any_link (link: &Link, message: &Message) {
impl EventLoop for AutolinkModule { impl EventLoop for AutolinkModule {
fn run (&self, _: Box<ExtSender<Event>>, receiver: Receiver<Arc<Envelope>>) { fn run (&self, _: Box<ExtSender<Event>>, receiver: Receiver<Arc<Envelope>>) {
let link_regex = Regex::new(r"\[\[([^\[\]]*)\]\]").expect("Invalid regex..."); let searcher = create_searcher(&self.searcher_config);
let mut searchers = AggregateSearcher::new();
searchers.add_searcher("mtg", Box::new(MtgSearcher::new()));
searchers.add_searcher("ygo", Box::new(YugiohSearcher::new()));
searchers.add_searcher("ygp", Box::new(MediawikiSearcher::new(String::from("https://yugipedia.com/wiki/"))));
searchers.add_searcher("pk", Box::new(MediawikiSearcher::new(String::from("https://bulbapedia.bulbagarden.net/wiki/"))));
searchers.add_searcher("gp", Box::new(MediawikiSearcher::new(String::from("https://gammapedia.monarch-pass.net/wiki/"))));
searchers.add_searcher("ip", Box::new(MediawikiSearcher::new(String::from("http://infinitypedia.org/wiki/"))));
searchers.add_searcher("gcl", Box::new(MediawikiSearcher::new(String::from("https://glitchcity.info/wiki/"))));
searchers.add_searcher("wp", Box::new(MediawikiSearcher::new(String::from("https://en.wikipedia.org/wiki/"))));
let mut searcher_cache = BTreeMap::new(); let mut searcher_cache = BTreeMap::new();
loop { loop {
@ -97,9 +130,9 @@ impl EventLoop for AutolinkModule {
Ok(envelope) => { Ok(envelope) => {
if let Event::Message { ref message } = envelope.event { if let Event::Message { ref message } = envelope.event {
debug!("Received message from module {:?}... {:?}", envelope.from, message.content); debug!("Received message from module {:?}... {:?}", envelope.from, message.content);
for cap in link_regex.captures_iter(&message.content) { for cap in self.pattern.captures_iter(&message.content) {
let term = cap[1].to_owned(); let term = cap[1].to_owned();
if let &mut Some(ref mut item) = searcher_cache.entry(term.to_owned()).or_insert_with(|| searchers.exact_search(&term)) { if let &mut Some(ref mut item) = searcher_cache.entry(term.to_owned()).or_insert_with(|| searcher.exact_search(&term)) {
print_any_link(item, message); print_any_link(item, message);
if let Some(card) = item.downcast_ref::<MtgCard>() { if let Some(card) = item.downcast_ref::<MtgCard>() {
print_mtg_card(card, message); print_mtg_card(card, message);

62
src/modules/cat.rs Executable file
View File

@ -0,0 +1,62 @@
use modules::EventLoop;
use toml::value::Table;
use std::sync::Arc;
use std::sync::mpsc::Receiver;
use transformable_channels::mpsc::ExtSender;
use helpers::command::split_command;
use event::{Event, Envelope};
use i_can_has_cat::Cats;
pub struct CatModule {
prefix: String
}
impl CatModule {
pub fn new (_: &Table, configuration: &Table) -> Box<EventLoop> {
let prefix = configuration.get("prefix")
.and_then(|value| value.as_str())
.unwrap_or("?cat");
Box::new(CatModule {
prefix: String::from(prefix)
})
}
}
impl EventLoop for CatModule {
fn run(&self, _: Box<ExtSender<Event>>, receiver: Receiver<Arc<Envelope>>) {
let cats = Cats::new();
loop {
match receiver.recv() {
Ok(envelope) => {
match envelope.event {
Event::Message { ref message } => {
debug!("Received message from module {:?}... {:?}", envelope.from, message.content);
match split_command(&message.content) {
Some((command, argument)) => {
if command == self.prefix {
let cat = if !argument.is_empty() {
cats.random_image_of_category(argument)
} else {
cats.random_image()
};
if let Ok(cat) = cat {
message.reply(&cat.url);
}
}
},
_ => {}
}
}
_ => ()
}
}
Err(error) => { error!("Error {:?}", error) }
}
}
}
}

45
src/modules/discord.rs Normal file → Executable file
View File

@ -1,9 +1,12 @@
use discord; use discord;
use discord::Discord; use discord::Discord;
use discord::model::{Event, PossibleServer}; use discord::model::{Event, PossibleServer, ChannelId};
use modules::EventLoop; use modules::EventLoop;
use toml;
use toml::value::Table; use toml::value::Table;
use helpers::config::Config;
use event; use event;
@ -20,24 +23,30 @@ use {MessageSender, Message, User, Channel};
pub struct DiscordModule { pub struct DiscordModule {
token: String, token: String,
playing: String playing: String,
guilds: Vec<String>
} }
const DEFAULT_PLAYING: &'static str = "tenquestionmarks 0.0.3"; const DEFAULT_PLAYING: &'static str = "tenquestionmarks 0.0.4";
impl DiscordModule { impl DiscordModule {
pub fn new (_: &Table, configuration: &Table) -> Box<EventLoop> { pub fn new (_: &Table, configuration: &Table) -> Box<EventLoop> {
let token = configuration.get("token") let token = configuration.get_string("token").unwrap_or("");
.and_then(|value| value.as_str()) let playing = configuration.get_string("playing").unwrap_or(DEFAULT_PLAYING);
.unwrap_or("");
let playing = configuration.get("playing") let guilds = configuration.get_vec("guilds")
.and_then(|value| value.as_str()) .unwrap_or(vec![])
.unwrap_or(DEFAULT_PLAYING); .iter()
.map(toml::Value::as_str)
.filter(Option::is_some)
.map(Option::unwrap)
.map(String::from)
.collect();
Box::new(DiscordModule { Box::new(DiscordModule {
token: String::from(token), token: String::from(token),
playing: String::from(playing) playing: String::from(playing),
guilds: guilds
}) })
} }
} }
@ -124,6 +133,9 @@ impl EventLoop for DiscordModule {
} }
}); });
let mut known_guild_ids: Vec<String> = vec![];
let mut known_channel_ids: Vec<ChannelId> = vec![];
loop { loop {
let event = connection.recv_event(); let event = connection.recv_event();
debug!("Received event: {:?}", event); debug!("Received event: {:?}", event);
@ -132,8 +144,15 @@ impl EventLoop for DiscordModule {
Ok(Event::ServerCreate(server)) => { Ok(Event::ServerCreate(server)) => {
match server { match server {
PossibleServer::Online(server) => { PossibleServer::Online(server) => {
info!("Joined server: {}", server.name); let guild_id_as_string = format!("{}", server.id);
if !(self.guilds.is_empty() || self.guilds.contains(&guild_id_as_string)) {
continue;
}
known_guild_ids.push(guild_id_as_string);
info!("Joined guild: {} (id {})", server.name, server.id);
for channel in server.channels { for channel in server.channels {
known_channel_ids.push(channel.id);
info!(" - Joined channel: {}", channel.name); info!(" - Joined channel: {}", channel.name);
match sender.send(event::Event::SelfJoin { match sender.send(event::Event::SelfJoin {
@ -148,6 +167,10 @@ impl EventLoop for DiscordModule {
} }
}, },
Ok(Event::MessageCreate(message)) => { Ok(Event::MessageCreate(message)) => {
if !known_channel_ids.contains(&message.channel_id) {
continue;
}
let author = User { let author = User {
name: message.author.name.clone(), name: message.author.name.clone(),
sender: Box::new(DiscordMessageSender { sender: Box::new(DiscordMessageSender {

62
src/modules/dog.rs Executable file
View File

@ -0,0 +1,62 @@
use modules::EventLoop;
use toml::value::Table;
use std::sync::Arc;
use std::sync::mpsc::Receiver;
use transformable_channels::mpsc::ExtSender;
use helpers::command::split_command;
use event::{Event, Envelope};
use wow_such_doge::Dogs;
pub struct DogModule {
prefix: String
}
impl DogModule {
pub fn new (_: &Table, configuration: &Table) -> Box<EventLoop> {
let prefix = configuration.get("prefix")
.and_then(|value| value.as_str())
.unwrap_or("?dog");
Box::new(DogModule {
prefix: String::from(prefix)
})
}
}
impl EventLoop for DogModule {
fn run(&self, _: Box<ExtSender<Event>>, receiver: Receiver<Arc<Envelope>>) {
let dogs = Dogs::new();
loop {
match receiver.recv() {
Ok(envelope) => {
match envelope.event {
Event::Message { ref message } => {
debug!("Received message from module {:?}... {:?}", envelope.from, message.content);
match split_command(&message.content) {
Some((command, argument)) => {
if command == self.prefix {
let dog = if !argument.is_empty() {
dogs.random_image_by_breed(argument)
} else {
dogs.random_image()
};
if let Ok(dog) = dog {
message.reply(&dog);
}
}
},
_ => {}
}
}
_ => ()
}
}
Err(error) => { error!("Error {:?}", error) }
}
}
}
}

0
src/modules/echo.rs Normal file → Executable file
View File

0
src/modules/echobox.rs Normal file → Executable file
View File

47
src/modules/irc.rs Normal file → Executable file
View File

@ -1,5 +1,4 @@
use irc::client::prelude::*; use irc::client::prelude::*;
use irc::client::data::command::Command;
use modules::EventLoop; use modules::EventLoop;
use toml::value::Table; use toml::value::Table;
@ -50,7 +49,7 @@ impl IrcHandler {
} }
pub struct IrcMessageSender { pub struct IrcMessageSender {
irc: IrcServerWrapper, irc: IrcClientWrapper,
channel: String channel: String
} }
@ -70,49 +69,51 @@ impl Debug for IrcMessageSender {
} }
} }
fn make_user (prefix: &Option<String>, server: &IrcServer) -> Option<User> { fn make_user (prefix: &Option<String>, server: &IrcClient) -> Option<User> {
prefix.as_ref().and_then(|prefix| prefix.split("!").next()).map(|name| User { prefix.as_ref().and_then(|prefix| prefix.split("!").next()).map(|name| User {
name: name.to_owned(), name: name.to_owned(),
sender: Box::new(IrcMessageSender { sender: Box::new(IrcMessageSender {
irc: IrcServerWrapper::new(&server), irc: IrcClientWrapper::new(&server),
channel: name.to_owned() channel: name.to_owned()
}) })
}) })
} }
struct IrcServerWrapper { struct IrcClientWrapper {
server: IrcServer, client: IrcClient,
thread_local: CachedThreadLocal<IrcServer> thread_local: CachedThreadLocal<IrcClient>
} }
impl IrcServerWrapper { impl IrcClientWrapper {
pub fn new (server: &IrcServer) -> IrcServerWrapper { pub fn new (client: &IrcClient) -> IrcClientWrapper {
IrcServerWrapper { IrcClientWrapper {
server: server.clone(), client: client.clone(),
thread_local: CachedThreadLocal::new() thread_local: CachedThreadLocal::new()
} }
} }
pub fn get (&self) -> &IrcServer { pub fn get (&self) -> &IrcClient {
self.thread_local.get_or(|| Box::new(self.server.clone())) self.thread_local.get_or(|| Box::new(self.client.clone()))
} }
} }
unsafe impl Sync for IrcServerWrapper {} unsafe impl Sync for IrcClientWrapper {}
impl EventLoop for IrcHandler { impl EventLoop for IrcHandler {
fn run (&self, sender: Box<ExtSender<event::Event>>, receiver: Receiver<Arc<event::Envelope>>) { fn run (&self, sender: Box<ExtSender<event::Event>>, receiver: Receiver<Arc<event::Envelope>>) {
let server = IrcServer::from_config(self.config.clone()).unwrap(); let client = IrcClient::from_config(self.config.clone()).unwrap();
server.identify().unwrap(); client.identify().unwrap();
crossbeam::scope(|scope| { crossbeam::scope(|scope| {
let server_sender = server.clone(); let client_sender = client.clone();
scope.spawn(move || { scope.spawn(move || {
loop { loop {
if let Ok(envelope) = receiver.recv() { if let Ok(envelope) = receiver.recv() {
if let event::Event::Message { ref message } = envelope.event { if let event::Event::Message { ref message } = envelope.event {
if let Some(ref channel) = message.channel { if let Some(ref channel) = message.channel {
server_sender.send_privmsg(&channel.name, &message.content); if let Err(error) = client_sender.send_privmsg(&channel.name, &message.content) {
error!("Failed to send IRC message: {}", error);
}
} }
} }
} else { } else {
@ -121,11 +122,10 @@ impl EventLoop for IrcHandler {
} }
}); });
for server_message in server.iter() { client.for_each_incoming(|irc_message| {
if let Ok(irc_message) = server_message {
match irc_message.command { match irc_message.command {
Command::PRIVMSG(channel, message) => { Command::PRIVMSG(channel, message) => {
if let Some(author) = make_user(&irc_message.prefix, &server) { if let Some(author) = make_user(&irc_message.prefix, &client) {
let message = Message { let message = Message {
author: author, author: author,
content: message, content: message,
@ -134,7 +134,7 @@ impl EventLoop for IrcHandler {
description: "".to_owned(), description: "".to_owned(),
topic: "".to_owned(), topic: "".to_owned(),
sender: Box::new(IrcMessageSender { sender: Box::new(IrcMessageSender {
irc: IrcServerWrapper::new(&server), irc: IrcClientWrapper::new(&client),
channel: channel.clone() channel: channel.clone()
}) })
}) })
@ -147,8 +147,7 @@ impl EventLoop for IrcHandler {
}, },
_ => {} _ => {}
} }
} }).unwrap();
}
}); });
} }
} }

12
src/modules/loader.rs Normal file → Executable file
View File

@ -5,16 +5,18 @@ use std::fmt;
use toml::value::Table; use toml::value::Table;
use modules::{Module, EventLoop}; use modules::{Module, EventLoop};
use modules::discord::DiscordModule; //use modules::discord::DiscordModule;
use modules::lua::LuaModule; use modules::lua::LuaModule;
use modules::stdin::StdinModule; use modules::stdin::StdinModule;
use modules::echo::EchoModule; use modules::echo::EchoModule;
use modules::random::RandomModule; use modules::random::RandomModule;
use modules::pvn::PvnModule; //use modules::pvn::PvnModule;
use modules::echobox::EchoboxModule; use modules::echobox::EchoboxModule;
use modules::autolink::AutolinkModule; use modules::autolink::AutolinkModule;
use modules::logger::LoggerModule; use modules::logger::LoggerModule;
use modules::irc::IrcHandler; use modules::irc::IrcHandler;
//use modules::dog::DogModule;
//use modules::cat::CatModule;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -25,16 +27,18 @@ pub struct ModuleLoader {
impl ModuleLoader { impl ModuleLoader {
pub fn new () -> ModuleLoader { pub fn new () -> ModuleLoader {
let mut types = BTreeMap::new(); let mut types = BTreeMap::new();
types.insert("discord", DiscordModule::new as fn(&Table, &Table) -> Box<EventLoop>); //types.insert("discord", DiscordModule::new as fn(&Table, &Table) -> Box<EventLoop>);
types.insert("lua", LuaModule::new as fn(&Table, &Table) -> Box<EventLoop>); types.insert("lua", LuaModule::new as fn(&Table, &Table) -> Box<EventLoop>);
types.insert("stdin", StdinModule::new as fn(&Table, &Table) -> Box<EventLoop>); types.insert("stdin", StdinModule::new as fn(&Table, &Table) -> Box<EventLoop>);
types.insert("echo", EchoModule::new as fn(&Table, &Table) -> Box<EventLoop>); types.insert("echo", EchoModule::new as fn(&Table, &Table) -> Box<EventLoop>);
types.insert("random", RandomModule::new as fn(&Table, &Table) -> Box<EventLoop>); types.insert("random", RandomModule::new as fn(&Table, &Table) -> Box<EventLoop>);
types.insert("pvn", PvnModule::new as fn(&Table, &Table) -> Box<EventLoop>); //types.insert("pvn", PvnModule::new as fn(&Table, &Table) -> Box<EventLoop>);
types.insert("echobox", EchoboxModule::new as fn(&Table, &Table) -> Box<EventLoop>); types.insert("echobox", EchoboxModule::new as fn(&Table, &Table) -> Box<EventLoop>);
types.insert("autolink", AutolinkModule::new as fn(&Table, &Table) -> Box<EventLoop>); types.insert("autolink", AutolinkModule::new as fn(&Table, &Table) -> Box<EventLoop>);
types.insert("logger", LoggerModule::new as fn(&Table, &Table) -> Box<EventLoop>); types.insert("logger", LoggerModule::new as fn(&Table, &Table) -> Box<EventLoop>);
types.insert("irc", IrcHandler::new as fn(&Table, &Table) -> Box<EventLoop>); types.insert("irc", IrcHandler::new as fn(&Table, &Table) -> Box<EventLoop>);
//types.insert("cat", CatModule::new as fn(&Table, &Table) -> Box<EventLoop>);
//types.insert("dog", DogModule::new as fn(&Table, &Table) -> Box<EventLoop>);
ModuleLoader { ModuleLoader {
types: types types: types
} }

0
src/modules/logger.rs Normal file → Executable file
View File

0
src/modules/lua.rs Normal file → Executable file
View File

6
src/modules/mod.rs Normal file → Executable file
View File

@ -1,13 +1,15 @@
pub mod lua; pub mod lua;
pub mod discord; //pub mod discord;
pub mod stdin; pub mod stdin;
pub mod echo; pub mod echo;
pub mod random; pub mod random;
pub mod pvn; //pub mod pvn;
pub mod echobox; pub mod echobox;
pub mod autolink; pub mod autolink;
pub mod logger; pub mod logger;
pub mod irc; pub mod irc;
//pub mod cat;
//pub mod dog;
pub mod loader; pub mod loader;

0
src/modules/pvn.rs Normal file → Executable file
View File

1
src/modules/random.rs Normal file → Executable file
View File

@ -63,6 +63,7 @@ impl EventLoop for RandomModule {
if let Some(captures) = pattern.captures(&message.content) { if let Some(captures) = pattern.captures(&message.content) {
let mut response = String::new(); let mut response = String::new();
captures.expand(&rand::sample(&mut rng, &responses, 1)[0], &mut response); captures.expand(&rand::sample(&mut rng, &responses, 1)[0], &mut response);
response = response.replace("$sender", &message.author.name);
message.reply(&response); message.reply(&response);
} }
}, },

0
src/modules/stdin.rs Normal file → Executable file
View File

0
tenquestionmarks.toml Normal file → Executable file
View File