add a rudimentary irc module
This commit is contained in:
parent
906b5709d0
commit
c6dc3f15b8
@ -16,6 +16,8 @@ time = "0.1"
|
|||||||
regex = "0.2"
|
regex = "0.2"
|
||||||
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)
|
||||||
|
thread_local = "0.3"
|
||||||
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" }
|
||||||
|
@ -8,6 +8,8 @@ extern crate transformable_channels;
|
|||||||
extern crate stc;
|
extern crate stc;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
extern crate multimap;
|
extern crate multimap;
|
||||||
|
extern crate irc;
|
||||||
|
extern crate thread_local;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate hlua;
|
extern crate hlua;
|
||||||
|
154
src/modules/irc.rs
Normal file
154
src/modules/irc.rs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
use irc::client::prelude::*;
|
||||||
|
use irc::client::data::command::Command;
|
||||||
|
|
||||||
|
use modules::EventLoop;
|
||||||
|
use toml::value::Table;
|
||||||
|
|
||||||
|
use event;
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::sync::mpsc::Receiver;
|
||||||
|
use transformable_channels::mpsc::ExtSender;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
|
use crossbeam;
|
||||||
|
|
||||||
|
use thread_local::CachedThreadLocal;
|
||||||
|
use {MessageSender, Message, User, Channel};
|
||||||
|
|
||||||
|
pub struct IrcHandler {
|
||||||
|
config: Config
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_NICK: &'static str = "tenquestionmarks";
|
||||||
|
|
||||||
|
impl IrcHandler {
|
||||||
|
pub fn new (_: &Table, configuration: &Table) -> Box<EventLoop> {
|
||||||
|
Box::new(IrcHandler {
|
||||||
|
config: Config {
|
||||||
|
nickname: Some(configuration.get("nickname")
|
||||||
|
.and_then(|value| value.as_str())
|
||||||
|
.unwrap_or(DEFAULT_NICK)
|
||||||
|
.to_owned()),
|
||||||
|
server: Some(configuration.get("server")
|
||||||
|
.and_then(|value| value.as_str())
|
||||||
|
.expect("Expected server in IRC config")
|
||||||
|
.to_owned()),
|
||||||
|
channels: Some(configuration.get("channels")
|
||||||
|
.and_then(|value| value.as_array())
|
||||||
|
.map(|value| value.to_vec())
|
||||||
|
.unwrap_or(vec![])
|
||||||
|
.into_iter()
|
||||||
|
.map(|value| { String::from(value.as_str().unwrap()) })
|
||||||
|
.collect()),
|
||||||
|
.. Default::default()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IrcMessageSender {
|
||||||
|
irc: IrcServerWrapper,
|
||||||
|
channel: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MessageSender for IrcMessageSender {
|
||||||
|
fn send_message (&self, message: &str) {
|
||||||
|
debug!("Send message to channel {:?}: {:?}", self.channel, message);
|
||||||
|
match self.irc.get().send_privmsg(&self.channel, message) {
|
||||||
|
Ok(_) => { debug!("Send message succeeded"); },
|
||||||
|
Err(err) => { error!("Send message failed: {:?}", err) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for IrcMessageSender {
|
||||||
|
fn fmt (&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(formatter, "IrcMessageSender {{ channel: {:?} }}", self.channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_user (prefix: &Option<String>, server: &IrcServer) -> Option<User> {
|
||||||
|
prefix.as_ref().and_then(|prefix| prefix.split("!").next()).map(|name| User {
|
||||||
|
name: name.to_owned(),
|
||||||
|
sender: Box::new(IrcMessageSender {
|
||||||
|
irc: IrcServerWrapper::new(&server),
|
||||||
|
channel: name.to_owned()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IrcServerWrapper {
|
||||||
|
server: IrcServer,
|
||||||
|
thread_local: CachedThreadLocal<IrcServer>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrcServerWrapper {
|
||||||
|
pub fn new (server: &IrcServer) -> IrcServerWrapper {
|
||||||
|
IrcServerWrapper {
|
||||||
|
server: server.clone(),
|
||||||
|
thread_local: CachedThreadLocal::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get (&self) -> &IrcServer {
|
||||||
|
self.thread_local.get_or(|| Box::new(self.server.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for IrcServerWrapper {}
|
||||||
|
|
||||||
|
impl EventLoop for IrcHandler {
|
||||||
|
fn run (&self, sender: Box<ExtSender<event::Event>>, receiver: Receiver<Arc<event::Envelope>>) {
|
||||||
|
let server = IrcServer::from_config(self.config.clone()).unwrap();
|
||||||
|
server.identify().unwrap();
|
||||||
|
|
||||||
|
crossbeam::scope(|scope| {
|
||||||
|
let server_sender = server.clone();
|
||||||
|
scope.spawn(move || {
|
||||||
|
loop {
|
||||||
|
if let Ok(envelope) = receiver.recv() {
|
||||||
|
if let event::Event::Message { ref message } = envelope.event {
|
||||||
|
if let Some(ref channel) = message.channel {
|
||||||
|
server_sender.send_privmsg(&channel.name, &message.content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for server_message in server.iter() {
|
||||||
|
if let Ok(irc_message) = server_message {
|
||||||
|
match irc_message.command {
|
||||||
|
Command::PRIVMSG(channel, message) => {
|
||||||
|
if let Some(author) = make_user(&irc_message.prefix, &server) {
|
||||||
|
let message = Message {
|
||||||
|
author: author,
|
||||||
|
content: message,
|
||||||
|
channel: Some(Channel {
|
||||||
|
name: channel.clone(),
|
||||||
|
description: "".to_owned(),
|
||||||
|
topic: "".to_owned(),
|
||||||
|
sender: Box::new(IrcMessageSender {
|
||||||
|
irc: IrcServerWrapper::new(&server),
|
||||||
|
channel: channel.clone()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = sender.send(event::Event::Message { message: message }) {
|
||||||
|
error!("Error sending message event: {:?}", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ 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 std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ impl ModuleLoader {
|
|||||||
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>);
|
||||||
ModuleLoader {
|
ModuleLoader {
|
||||||
types: types
|
types: types
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ 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 loader;
|
pub mod loader;
|
||||||
|
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
[general]
|
[general]
|
||||||
foo = "bar"
|
foo = "bar"
|
||||||
|
|
||||||
|
[irc]
|
||||||
|
server = "irc.rizon.net"
|
||||||
|
channels = ["#eightbar"]
|
||||||
|
|
||||||
[discord]
|
[discord]
|
||||||
token = "your token here"
|
token = "your token here"
|
||||||
|
|
||||||
[stdin]
|
[stdin]
|
||||||
|
|
||||||
[echo]
|
[echo]
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord", "irc"]
|
||||||
prefix = "?echo"
|
prefix = "?echo"
|
||||||
|
|
||||||
[no]
|
[no]
|
||||||
type = "random"
|
type = "random"
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord", "irc"]
|
||||||
prefix = "?no"
|
prefix = "?no"
|
||||||
responses = [
|
responses = [
|
||||||
"https://www.youtube.com/watch?v=WWaLxFIVX1s", # Darth Vader
|
"https://www.youtube.com/watch?v=WWaLxFIVX1s", # Darth Vader
|
||||||
@ -38,7 +42,7 @@ responses = [
|
|||||||
|
|
||||||
[yes]
|
[yes]
|
||||||
type = "random"
|
type = "random"
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord", "irc"]
|
||||||
prefix = "?yes"
|
prefix = "?yes"
|
||||||
responses = [
|
responses = [
|
||||||
"https://www.youtube.com/watch?v=JPVaDaynNKM", # Captain Falcon
|
"https://www.youtube.com/watch?v=JPVaDaynNKM", # Captain Falcon
|
||||||
@ -61,15 +65,15 @@ responses = [
|
|||||||
|
|
||||||
[chk]
|
[chk]
|
||||||
type = "random"
|
type = "random"
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord", "irc"]
|
||||||
prefix = "?chk"
|
prefix = "?chk"
|
||||||
responses = ["ack"]
|
responses = ["ack"]
|
||||||
|
|
||||||
[pvn]
|
[pvn]
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord", "irc"]
|
||||||
|
|
||||||
[echobox]
|
[echobox]
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord", "irc"]
|
||||||
|
|
||||||
[lua]
|
[lua]
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord"]
|
||||||
@ -91,20 +95,20 @@ end
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
[autolink]
|
[autolink]
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord", "irc"]
|
||||||
|
|
||||||
[logger]
|
[logger]
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord", "irc"]
|
||||||
filters = [{ username = "Dave" }, { username = "Kevin" }]
|
#filters = [{ username = "Dave" }, { username = "Kevin" }]
|
||||||
|
|
||||||
[icced]
|
[icced]
|
||||||
type = "random"
|
type = "random"
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord", "irc"]
|
||||||
pattern = "\\bicc?ed?\\b"
|
pattern = "\\bicc?ed?\\b"
|
||||||
responses = ["Did some carbon-based lifeform just say **I C E**?"]
|
responses = ["Did some carbon-based lifeform just say **I C E**?"]
|
||||||
|
|
||||||
[trout]
|
[trout]
|
||||||
type = "random"
|
type = "random"
|
||||||
parents = ["stdin", "discord"]
|
parents = ["stdin", "discord", "irc"]
|
||||||
pattern = "^?slap (.*)"
|
pattern = "^?slap (.*)"
|
||||||
responses = ["/me slaps $1 around a bit with a large trout", "/me slaps $1 around a bit with a large brick"]
|
responses = ["/me slaps $1 around a bit with a large trout", "/me slaps $1 around a bit with a large brick"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user