mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 17:47:03 +00:00
* lua: Restore missing test log output * lua: Use logger for test assert_async output * lua: add InboundMessage bindings * lua: bind BeforeMessageStored function --------- Signed-off-by: James Hillyerd <james@hillyerd.com>
224 lines
5.0 KiB
Go
224 lines
5.0 KiB
Go
package luahost
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
lua "github.com/yuin/gopher-lua"
|
|
)
|
|
|
|
const (
|
|
inbucketName = "inbucket"
|
|
inbucketBeforeName = "inbucket_before"
|
|
inbucketAfterName = "inbucket_after"
|
|
)
|
|
|
|
// Inbucket is the primary Lua interface data structure.
|
|
type Inbucket struct {
|
|
After InbucketAfterFuncs
|
|
Before InbucketBeforeFuncs
|
|
}
|
|
|
|
// InbucketAfterFuncs holds references to Lua extension functions to be called async
|
|
// after Inbucket handles an event.
|
|
type InbucketAfterFuncs struct {
|
|
MessageDeleted *lua.LFunction
|
|
MessageStored *lua.LFunction
|
|
}
|
|
|
|
// InbucketBeforeFuncs holds references to Lua extension functions to be called
|
|
// before Inbucket handles an event.
|
|
type InbucketBeforeFuncs struct {
|
|
MailAccepted *lua.LFunction
|
|
MessageStored *lua.LFunction
|
|
}
|
|
|
|
func registerInbucketTypes(ls *lua.LState) {
|
|
// inbucket type.
|
|
mt := ls.NewTypeMetatable(inbucketName)
|
|
ls.SetField(mt, "__index", ls.NewFunction(inbucketIndex))
|
|
|
|
// inbucket global var.
|
|
ud := wrapInbucket(ls, &Inbucket{})
|
|
ls.SetGlobal(inbucketName, ud)
|
|
|
|
// inbucket.after type.
|
|
mt = ls.NewTypeMetatable(inbucketAfterName)
|
|
ls.SetField(mt, "__index", ls.NewFunction(inbucketAfterIndex))
|
|
ls.SetField(mt, "__newindex", ls.NewFunction(inbucketAfterNewIndex))
|
|
|
|
// inbucket.before type.
|
|
mt = ls.NewTypeMetatable(inbucketBeforeName)
|
|
ls.SetField(mt, "__index", ls.NewFunction(inbucketBeforeIndex))
|
|
ls.SetField(mt, "__newindex", ls.NewFunction(inbucketBeforeNewIndex))
|
|
}
|
|
|
|
func wrapInbucket(ls *lua.LState, val *Inbucket) *lua.LUserData {
|
|
ud := ls.NewUserData()
|
|
ud.Value = val
|
|
ls.SetMetatable(ud, ls.GetTypeMetatable(inbucketName))
|
|
|
|
return ud
|
|
}
|
|
|
|
func wrapInbucketAfter(ls *lua.LState, val *InbucketAfterFuncs) *lua.LUserData {
|
|
ud := ls.NewUserData()
|
|
ud.Value = val
|
|
ls.SetMetatable(ud, ls.GetTypeMetatable(inbucketAfterName))
|
|
|
|
return ud
|
|
}
|
|
|
|
func wrapInbucketBefore(ls *lua.LState, val *InbucketBeforeFuncs) *lua.LUserData {
|
|
ud := ls.NewUserData()
|
|
ud.Value = val
|
|
ls.SetMetatable(ud, ls.GetTypeMetatable(inbucketBeforeName))
|
|
|
|
return ud
|
|
}
|
|
|
|
func getInbucket(ls *lua.LState) (*Inbucket, error) {
|
|
lv := ls.GetGlobal(inbucketName)
|
|
if lv == nil {
|
|
return nil, errors.New("inbucket object was nil")
|
|
}
|
|
|
|
ud, ok := lv.(*lua.LUserData)
|
|
if !ok {
|
|
return nil, fmt.Errorf("inbucket object was type %s instead of UserData", lv.Type())
|
|
}
|
|
|
|
val, ok := ud.Value.(*Inbucket)
|
|
if !ok {
|
|
return nil, fmt.Errorf("inbucket object (%v) could not be cast", ud.Value)
|
|
}
|
|
|
|
return val, nil
|
|
}
|
|
|
|
func checkInbucket(ls *lua.LState, pos int) *Inbucket {
|
|
ud := ls.CheckUserData(pos)
|
|
if val, ok := ud.Value.(*Inbucket); ok {
|
|
return val
|
|
}
|
|
ls.ArgError(1, inbucketName+" expected")
|
|
return nil
|
|
}
|
|
|
|
func checkInbucketAfter(ls *lua.LState, pos int) *InbucketAfterFuncs {
|
|
ud := ls.CheckUserData(pos)
|
|
if val, ok := ud.Value.(*InbucketAfterFuncs); ok {
|
|
return val
|
|
}
|
|
ls.ArgError(1, inbucketAfterName+" expected")
|
|
return nil
|
|
}
|
|
|
|
func checkInbucketBefore(ls *lua.LState, pos int) *InbucketBeforeFuncs {
|
|
ud := ls.CheckUserData(pos)
|
|
if val, ok := ud.Value.(*InbucketBeforeFuncs); ok {
|
|
return val
|
|
}
|
|
ls.ArgError(1, inbucketBeforeName+" expected")
|
|
return nil
|
|
}
|
|
|
|
// inbucket getter.
|
|
func inbucketIndex(ls *lua.LState) int {
|
|
ib := checkInbucket(ls, 1)
|
|
field := ls.CheckString(2)
|
|
|
|
// Push the requested field's value onto the stack.
|
|
switch field {
|
|
case "after":
|
|
ls.Push(wrapInbucketAfter(ls, &ib.After))
|
|
case "before":
|
|
ls.Push(wrapInbucketBefore(ls, &ib.Before))
|
|
default:
|
|
// Unknown field.
|
|
ls.Push(lua.LNil)
|
|
}
|
|
|
|
return 1
|
|
}
|
|
|
|
// inbucket.after getter.
|
|
func inbucketAfterIndex(ls *lua.LState) int {
|
|
after := checkInbucketAfter(ls, 1)
|
|
field := ls.CheckString(2)
|
|
|
|
// Push the requested field's value onto the stack.
|
|
switch field {
|
|
case "message_deleted":
|
|
ls.Push(funcOrNil(after.MessageDeleted))
|
|
case "message_stored":
|
|
ls.Push(funcOrNil(after.MessageStored))
|
|
default:
|
|
// Unknown field.
|
|
ls.Push(lua.LNil)
|
|
}
|
|
|
|
return 1
|
|
}
|
|
|
|
// inbucket.after setter.
|
|
func inbucketAfterNewIndex(ls *lua.LState) int {
|
|
m := checkInbucketAfter(ls, 1)
|
|
index := ls.CheckString(2)
|
|
|
|
switch index {
|
|
case "message_deleted":
|
|
m.MessageDeleted = ls.CheckFunction(3)
|
|
case "message_stored":
|
|
m.MessageStored = ls.CheckFunction(3)
|
|
default:
|
|
ls.RaiseError("invalid inbucket.after index %q", index)
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
// inbucket.before getter.
|
|
func inbucketBeforeIndex(ls *lua.LState) int {
|
|
before := checkInbucketBefore(ls, 1)
|
|
field := ls.CheckString(2)
|
|
|
|
// Push the requested field's value onto the stack.
|
|
switch field {
|
|
case "mail_accepted":
|
|
ls.Push(funcOrNil(before.MailAccepted))
|
|
case "message_stored":
|
|
ls.Push(funcOrNil(before.MessageStored))
|
|
default:
|
|
// Unknown field.
|
|
ls.Push(lua.LNil)
|
|
}
|
|
|
|
return 1
|
|
}
|
|
|
|
// inbucket.before setter.
|
|
func inbucketBeforeNewIndex(ls *lua.LState) int {
|
|
m := checkInbucketBefore(ls, 1)
|
|
index := ls.CheckString(2)
|
|
|
|
switch index {
|
|
case "mail_accepted":
|
|
m.MailAccepted = ls.CheckFunction(3)
|
|
case "message_stored":
|
|
m.MessageStored = ls.CheckFunction(3)
|
|
default:
|
|
ls.RaiseError("invalid inbucket.before index %q", index)
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func funcOrNil(f *lua.LFunction) lua.LValue {
|
|
if f == nil {
|
|
return lua.LNil
|
|
}
|
|
|
|
return f
|
|
}
|