beefed up lua scripting support, the message
is now presented as a table/struct/object and lua now has access to a sender object which it can use to send messages downstream.
This commit is contained in:
parent
c6dc3f15b8
commit
b0c2928e78
@ -198,6 +198,14 @@ pub trait MessageSender : Sync + Send + std::fmt::Debug {
|
||||
fn send_message (&self, _: &str) {}
|
||||
}
|
||||
|
||||
pub struct NullMessageSender {}
|
||||
impl MessageSender for NullMessageSender {}
|
||||
impl std::fmt::Debug for NullMessageSender {
|
||||
fn fmt (&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(formatter, "NullMessageSender")
|
||||
}
|
||||
}
|
||||
|
||||
struct Subscription {
|
||||
pub name: String,
|
||||
pub filters: Vec<Box<EventFilter>>
|
||||
|
@ -4,10 +4,10 @@ use toml::Value;
|
||||
use toml::value::Table;
|
||||
|
||||
use hlua;
|
||||
use hlua::{Lua, LuaFunction, Push};
|
||||
use hlua::{Lua, LuaFunction, AnyHashableLuaValue, AnyLuaValue};
|
||||
|
||||
use {User, Message, Channel, NullMessageSender};
|
||||
use event::{Event, Envelope};
|
||||
use Message;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::Receiver;
|
||||
@ -16,6 +16,8 @@ use transformable_channels::mpsc::ExtSender;
|
||||
use std::path::Path;
|
||||
use std::fs::File;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct LuaModule {
|
||||
code: Option<String>,
|
||||
file: Option<String>,
|
||||
@ -42,15 +44,76 @@ fn set (lua: &mut Lua, key: &str, value: &Value) {
|
||||
}
|
||||
}
|
||||
|
||||
implement_lua_read!(Message);
|
||||
implement_lua_push!(Message, |mut metatable| {
|
||||
struct MessageWrapper {
|
||||
envelope: Arc<Envelope>
|
||||
}
|
||||
|
||||
implement_lua_read!(MessageWrapper);
|
||||
implement_lua_push!(MessageWrapper, |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)));
|
||||
index.set("content", hlua::function1(|wrapper: &MessageWrapper| {
|
||||
if let Event::Message { ref message } = wrapper.envelope.event {
|
||||
Some(message.content.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}));
|
||||
index.set("reply", hlua::function2(|wrapper: &MessageWrapper, reply: String| {
|
||||
if let Event::Message { ref message } = wrapper.envelope.event {
|
||||
message.reply(&reply);
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
struct SenderWrapper {
|
||||
sender: Box<ExtSender<Event>>
|
||||
}
|
||||
|
||||
implement_lua_read!(SenderWrapper);
|
||||
implement_lua_push!(SenderWrapper, |mut metatable| {
|
||||
let mut index = metatable.empty_array("__index");
|
||||
index.set("send", hlua::function2(|wrapper: &SenderWrapper, data: HashMap<AnyHashableLuaValue, AnyLuaValue>| {
|
||||
if let Some(&AnyLuaValue::LuaString(ref event_type)) = data.get(&AnyHashableLuaValue::LuaString("type".to_owned())) {
|
||||
match event_type.as_ref() {
|
||||
"message" => {
|
||||
wrapper.sender.send(Event::Message {
|
||||
message: Message {
|
||||
author: User {
|
||||
name: data.get(&AnyHashableLuaValue::LuaString("username".to_owned()))
|
||||
.and_then(|value| match value {
|
||||
&AnyLuaValue::LuaString (ref string_value) => Some(string_value.to_owned()),
|
||||
_ => None
|
||||
})
|
||||
.unwrap_or_else(|| "".to_owned()),
|
||||
sender: Box::new(NullMessageSender {})
|
||||
},
|
||||
channel: data.get(&AnyHashableLuaValue::LuaString("channel".to_owned()))
|
||||
.and_then(|value| match value {
|
||||
&AnyLuaValue::LuaString (ref string_value) => Some(string_value.to_owned()),
|
||||
_ => None
|
||||
}).map(|channel| Channel {
|
||||
name: channel,
|
||||
description: "".to_owned(),
|
||||
sender: Box::new(NullMessageSender {}),
|
||||
topic: "".to_owned()
|
||||
}),
|
||||
content: data.get(&AnyHashableLuaValue::LuaString("message".to_owned()))
|
||||
.and_then(|value| match value {
|
||||
&AnyLuaValue::LuaString (ref string_value) => Some(string_value.to_owned()),
|
||||
_ => None
|
||||
})
|
||||
.expect("Invalid message event passed in")
|
||||
}
|
||||
});
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
impl EventLoop for LuaModule {
|
||||
fn run (&self, _: Box<ExtSender<Event>>, receiver: Receiver<Arc<Envelope>>) {
|
||||
fn run (&self, sender: Box<ExtSender<Event>>, receiver: Receiver<Arc<Envelope>>) {
|
||||
let mut lua = Lua::new();
|
||||
lua.openlibs();
|
||||
|
||||
@ -58,6 +121,10 @@ impl EventLoop for LuaModule {
|
||||
set(&mut lua, key, value);
|
||||
}
|
||||
|
||||
lua.set("sender", SenderWrapper {
|
||||
sender: Box::new(sender.clone())
|
||||
});
|
||||
|
||||
match self.code {
|
||||
Some(ref code) => { lua.execute(&code).unwrap() },
|
||||
None => {
|
||||
@ -81,23 +148,9 @@ impl EventLoop for LuaModule {
|
||||
let on_message: Option<LuaFunction<_>> = 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();
|
||||
on_message.call_with_args::<(), _, _>(MessageWrapper {
|
||||
envelope: envelope.clone()
|
||||
}).unwrap();
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
@ -78,8 +78,8 @@ parents = ["stdin", "discord", "irc"]
|
||||
[lua]
|
||||
parents = ["stdin", "discord"]
|
||||
code = """
|
||||
function on_message (message, reply)
|
||||
reply("Lua says: " .. message)
|
||||
function on_message (message)
|
||||
message:reply("Lua says: " .. message:content())
|
||||
end
|
||||
"""
|
||||
foo = "bar"
|
||||
@ -89,8 +89,24 @@ type = "lua"
|
||||
parents = ["stdin", "discord"]
|
||||
filters = [{ username = "David" }]
|
||||
code = """
|
||||
function on_message (message, reply)
|
||||
reply("Lua2 says: " .. message)
|
||||
function on_message (message)
|
||||
message:reply("Lua2 says: " .. message:content())
|
||||
end
|
||||
"""
|
||||
|
||||
[lua3]
|
||||
type = "lua"
|
||||
children = ["lua", "irc"]
|
||||
code = """
|
||||
local clock = os.clock
|
||||
function sleep(n) -- seconds
|
||||
local t0 = clock()
|
||||
while clock() - t0 <= n do end
|
||||
end
|
||||
|
||||
while true do
|
||||
sender:send({type = "message", channel = "#eightbar", message = "Hello world!"})
|
||||
sleep(10)
|
||||
end
|
||||
"""
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user