diff --git a/src/lib.rs b/src/lib.rs index c046dac..2d95675 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,9 @@ extern crate pvn; extern crate echobox; extern crate transformable_channels; +#[macro_use] +extern crate hlua; + use std::collections::BTreeMap; use toml::Table; @@ -20,6 +23,7 @@ use std::sync::Arc; use std::sync::mpsc; use std::sync::mpsc::Sender; +use std::rc::Rc; use std::cell::{Cell, RefCell}; use transformable_channels::mpsc::TransformableSender; diff --git a/src/modules/discord.rs b/src/modules/discord.rs index 53198f2..47b24df 100644 --- a/src/modules/discord.rs +++ b/src/modules/discord.rs @@ -6,6 +6,7 @@ use modules::Module; use toml::Table; use event; +use event::Envelope; use std::sync::Arc; use std::sync::mpsc::Receiver; @@ -72,7 +73,7 @@ impl Module for DiscordModule { for channel in server.channels { info!(" - Joined channel: {}", channel.name); - match sender.send(event::Envelope::new(event::Event::SelfJoin { + match sender.send(Envelope::new(event::Event::SelfJoin { channel: Channel { name: channel.name, description: String::from(""), @@ -116,7 +117,7 @@ impl Module for DiscordModule { channel: Some(channel) }; - match sender.send(event::Envelope::new(event::Event::Message { message: message })) { + match sender.send(Envelope::new(event::Event::Message { message: message })) { Err(err) => error!("Error sending message event: {:?}", err), Ok(_) => {} } diff --git a/src/modules/lua.rs b/src/modules/lua.rs index e586990..0b0d606 100644 --- a/src/modules/lua.rs +++ b/src/modules/lua.rs @@ -1,14 +1,106 @@ use modules::Module; -use toml::Table; + +use toml::{Table, Value}; + +use hlua; +use hlua::{Lua, LuaFunction, Push}; + +use event::{Event, Envelope}; +use Message; + +use std::sync::Arc; +use std::sync::mpsc::Receiver; +use transformable_channels::mpsc::ExtSender; + +use std::path::Path; +use std::fs::File; pub struct LuaModule { - + code: Option, + file: Option, + variables: Table } impl LuaModule { - pub fn new (_: &Table) -> Box { - Box::new(LuaModule {}) + pub fn new (config: &Table) -> Box { + Box::new(LuaModule { + code: config.get("code").and_then(|value| value.as_str()).map(String::from), + file: config.get("file").and_then(|value| value.as_str()).map(String::from), + variables: config.clone() + }) } } -impl Module for LuaModule {} +fn set (lua: &mut Lua, key: &str, value: &Value) { + match value.clone() { + Value::String(string) => lua.set(key, string), + Value::Integer(integer) => lua.set(key, integer as i32), + Value::Float(float) => lua.set(key, float), + Value::Boolean(boolean) => lua.set(key, boolean), + _ => {} + } +} + +implement_lua_read!(Message); +implement_lua_push!(Message, |mut metatable| { + let mut index = metatable.empty_array("__index"); + index.set("content", hlua::function1(|message: &mut Message| message.content.clone())); + index.set("reply", hlua::function2(|message: &mut Message, reply: String| message.reply(&reply))); +}); + +impl Module for LuaModule { + fn run (&self, _: Box>, receiver: Receiver>) { + let mut lua = Lua::new(); + lua.openlibs(); + + for (key, value) in &self.variables { + set(&mut lua, key, value); + } + + match self.code { + Some(ref code) => { lua.execute(&code).unwrap() }, + None => { + match self.file { + Some(ref file) => { lua.execute_from_reader::<(), _>(File::open(&Path::new(file)).unwrap()).unwrap(); } + None => {} + } + } + } + + loop { + match receiver.recv() { + Ok(envelope) => { + match envelope.event { + Event::Message { ref message } => { + let on_message: Option> = lua.get("on_message"); + match on_message { + Some(mut on_message) => { + /* + * What this does is clone the envelope reference (an Arc - atomic refcounted) + * and pass it into the reply_callback, where it becomes owned by the closure + * (since it's a move closure). We then pass this callback into the lua code, + * where it can be used to send a reply. + * + * TODO: Replace this with a table (struct/class) which has a + * reply() method. + */ + let envelope_clone = envelope.clone(); + let reply_callback = hlua::function1(move |reply: String| { + match envelope_clone.event { + Event::Message { ref message } => message.reply(&reply), + _ => {} + } + }); + on_message.call_with_args::<(), _, _>((message.content.clone(), reply_callback)).unwrap(); + }, + None => {} + } + } + _ => () + } + } + Err(error) => { error!("Error {:?}", error) } + } + } + } +}