extern crate toml; extern crate crossbeam; extern crate discord; extern crate rand; extern crate pvn; extern crate echobox; use std::collections::BTreeMap; use toml::Table; mod modules; use modules::Module; use modules::loader::{ModuleLoader, ModuleLoaderError}; mod event; use event::Event; use std::sync::Arc; use std::sync::mpsc; use std::sync::mpsc::Sender; mod helpers; #[macro_use] extern crate log; pub struct Tenquestionmarks { modules: BTreeMap> } impl Tenquestionmarks { pub fn with_modules (modules: BTreeMap>) -> Tenquestionmarks { let tqm = Tenquestionmarks { modules: modules }; for (key, module) in &tqm.modules { module.register(&tqm); } tqm } pub fn from_configuration (configuration: Table) -> Result { let loader = ModuleLoader::new(); let modules = loader.load_from_configuration(configuration)?; Result::Ok(Tenquestionmarks::with_modules(modules)) } pub fn run (&self) { crossbeam::scope(|scope| { // Our event channel. // Modules push events to tenquestionmarks using this channel. let (ref sender, ref receiver) = mpsc::channel(); // Module event consumer threads. // tenquestionmarks propagates all events to each Module through these // channels. let senders: BTreeMap<&str, Sender>> = self.modules.iter().map(|(key, module)| { let (sender, receiver) = mpsc::channel(); info!("Spawning consumer thread for \"{}\"", key); scope.spawn(move || { module.consume_events(receiver); info!("Consumer thread for \"{}\" is exiting", key); }); (&key[..], sender) }).collect(); // Module event producer threads. // Each Module will produce events which tenquestionmarks will push // into all other Modules. for (key, module) in self.modules.iter() { let module_sender = sender.clone(); info!("Spawning producer thread for \"{}\"", key); scope.spawn(move || { module.produce_events(module_sender); info!("Producer thread for \"{}\" is exiting", key); }); } // tenquestionmarks main event loop. // tenquestionmarks receives events produced by Modules and pushes them // into all other Modules loop { match receiver.recv() { Ok(event) => { for (key, sender) in &senders { match sender.send(event.clone()) { Err(err) => debug!("Failed to dispatch event to module \"{}\": {:?}", key, err), Ok(_) => {} } } }, Err(err) => { error!("Failed to receive event in main event loop: {:?}", err); } } } }); } } pub struct Message { content: String, author: User, channel: Option } impl Message { fn reply (&self, message: &str) { match self.channel { Some(ref channel) => channel.send(message), None => self.author.send(message) } } } pub struct Channel { name: String, description: String, topic: String, sender: Box } impl Channel { pub fn send (&self, message: &str) { self.sender.send_message(message); } } pub struct User { name: String, sender: Box } impl User { pub fn send (&self, message: &str) { self.sender.send_message(message); } } pub trait MessageSender : Sync + Send { fn send_message (&self, message: &str) {} }