Compare commits
13 Commits
master
...
ssl_update
Author | SHA1 | Date | |
---|---|---|---|
496ba89d94 | |||
|
ae9945403f | ||
|
3a06d98247 | ||
|
9052a3b26b | ||
|
4bfe6e2aec | ||
|
a698450c1e | ||
|
0d4718c3f3 | ||
|
cbf1688bdd | ||
|
138e4edc08 | ||
|
5fb167a8d0 | ||
|
9271c39ce2 | ||
|
4e6d648d18 | ||
|
1c870b58e4 |
17
Cargo.toml
17
Cargo.toml
@ -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
lua/dailies.lua
Normal file → Executable file
0
lua/dailies.lua
Normal file → Executable file
0
src/event/filter.rs
Normal file → Executable file
0
src/event/filter.rs
Normal file → Executable file
0
src/event/mod.rs
Normal file → Executable file
0
src/event/mod.rs
Normal file → Executable file
0
src/helpers/command.rs
Normal file → Executable file
0
src/helpers/command.rs
Normal file → Executable file
18
src/helpers/config.rs
Executable file
18
src/helpers/config.rs
Executable 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
1
src/helpers/mod.rs
Normal file → Executable file
@ -1 +1,2 @@
|
|||||||
pub mod command;
|
pub mod command;
|
||||||
|
pub mod config;
|
||||||
|
4
src/lib.rs
Normal file → Executable file
4
src/lib.rs
Normal file → Executable 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
0
src/main.rs
Normal file → Executable file
77
src/modules/autolink.rs
Normal file → Executable file
77
src/modules/autolink.rs
Normal file → Executable 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 print_mtg_card (card: &MtgCard, message: &Message) {
|
fn create_searcher (configuration: &Table) -> AggregateSearcher {
|
||||||
message.reply(&format!("{}", card.image_url));
|
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
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ref cost) = card.cost {
|
fn print_mtg_card (card: &MtgCard, message: &Message) {
|
||||||
|
if let Some(ref image_uri) = card.image_uris.get("normal") {
|
||||||
|
message.reply(&format!("{}", image_uri));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
62
src/modules/cat.rs
Executable 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
45
src/modules/discord.rs
Normal file → Executable 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
62
src/modules/dog.rs
Executable 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
0
src/modules/echo.rs
Normal file → Executable file
0
src/modules/echobox.rs
Normal file → Executable file
0
src/modules/echobox.rs
Normal file → Executable file
83
src/modules/irc.rs
Normal file → Executable file
83
src/modules/irc.rs
Normal file → Executable 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,34 +122,32 @@ 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, &client) {
|
||||||
if let Some(author) = make_user(&irc_message.prefix, &server) {
|
let message = Message {
|
||||||
let message = Message {
|
author: author,
|
||||||
author: author,
|
content: message,
|
||||||
content: message,
|
channel: Some(Channel {
|
||||||
channel: Some(Channel {
|
name: channel.clone(),
|
||||||
name: channel.clone(),
|
description: "".to_owned(),
|
||||||
description: "".to_owned(),
|
topic: "".to_owned(),
|
||||||
topic: "".to_owned(),
|
sender: Box::new(IrcMessageSender {
|
||||||
sender: Box::new(IrcMessageSender {
|
irc: IrcClientWrapper::new(&client),
|
||||||
irc: IrcServerWrapper::new(&server),
|
channel: channel.clone()
|
||||||
channel: channel.clone()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
};
|
})
|
||||||
|
};
|
||||||
|
|
||||||
if let Err(err) = sender.send(event::Event::Message { message: message }) {
|
if let Err(err) = sender.send(event::Event::Message { message: message }) {
|
||||||
error!("Error sending message event: {:?}", err)
|
error!("Error sending message event: {:?}", err)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => {}
|
},
|
||||||
}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}).unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
src/modules/loader.rs
Normal file → Executable file
12
src/modules/loader.rs
Normal file → Executable 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
0
src/modules/logger.rs
Normal file → Executable file
0
src/modules/lua.rs
Normal file → Executable file
0
src/modules/lua.rs
Normal file → Executable file
6
src/modules/mod.rs
Normal file → Executable file
6
src/modules/mod.rs
Normal file → Executable 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
0
src/modules/pvn.rs
Normal file → Executable file
1
src/modules/random.rs
Normal file → Executable file
1
src/modules/random.rs
Normal file → Executable 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
0
src/modules/stdin.rs
Normal file → Executable file
0
tenquestionmarks.toml
Normal file → Executable file
0
tenquestionmarks.toml
Normal file → Executable file
Loading…
x
Reference in New Issue
Block a user