mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-19 02:27:03 +00:00
Provide inbucket object in Lua (#351)
* fix delve fortify thingy * Expose inbucket.after.message_stored in lua * Expose inbucket.after.message_deleted in lua * Expose inbucket.before.mail_accepted in lua
This commit is contained in:
218
pkg/extension/luahost/bind_inbucket.go
Normal file
218
pkg/extension/luahost/bind_inbucket.go
Normal file
@@ -0,0 +1,218 @@
|
||||
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
|
||||
}
|
||||
|
||||
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))
|
||||
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)
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user