feat(bait): add error hook and hooks function (closes #205)

an `error` hook is now thrown when an event in lua
throws an error (errors from go side should not happen)
it includes the event name, handler, and error message

a hooks function has also been added. it returns a table
of handlers for a specific event.
reuse-runner-2
TorchedSammy 2022-10-11 17:41:13 -04:00
parent 117a4580b4
commit 068a5b5149
Signed by: sammyette
GPG Key ID: 904FC49417B44DCD
4 changed files with 50 additions and 3 deletions

View File

@ -6,3 +6,8 @@ Here is the format for a doc for a hook:
`<args>` just means the arguments of the hook. If a hook doc has the format
of `arg...`, it means the hook can take/recieve any number of `arg`.
+ error -> eventName, handler, err > Emitted when there is an error in
an event handler. The `eventName` is the name of the event the handler
is for, the `handler` is the callback function, and `err` is the error
message.

View File

@ -1,6 +1,8 @@
package bait
import (
"errors"
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
@ -72,8 +74,12 @@ func (b *Bait) Emit(event string, args ...interface{}) {
}
_, err := rt.Call1(b.rtm.MainThread(), funcVal, luaArgs...)
if err != nil {
// panicking here won't actually cause hilbish to panic and instead will
// print the error and remove the hook. reference the recoverer function in lua.go
if event != "error" {
b.Emit("error", event, handle.luaCaller, err.Error())
return
}
// if there is an error in an error event handler, panic instead
// (calls the go recoverer function)
panic(err)
}
} else {
@ -187,6 +193,7 @@ func (b *Bait) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
"catchOnce": util.LuaExport{b.bcatchOnce, 2, false},
"throw": util.LuaExport{b.bthrow, 1, true},
"release": util.LuaExport{b.brelease, 2, false},
"hooks": util.LuaExport{b.bhooks, 1, false},
}
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
@ -289,3 +296,33 @@ func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
// hooks(name) -> {cb, cb...}
// Returns a table with hooks on the event with `name`.
func (b *Bait) bhooks(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
evName, err := c.StringArg(0)
if err != nil {
return nil, err
}
noHooks := errors.New("no hooks for event " + evName)
handlers := b.handlers[evName]
if handlers == nil {
return nil, noHooks
}
luaHandlers := rt.NewTable()
for _, handler := range handlers {
if handler.typ != luaListener { continue }
luaHandlers.Set(rt.IntValue(luaHandlers.Len() + 1), rt.FunctionValue(handler.luaCaller))
}
if luaHandlers.Len() == 0 {
return nil, noHooks
}
return c.PushingNext1(t.Runtime, rt.TableValue(luaHandlers)), nil
}

2
lua.go
View File

@ -49,7 +49,7 @@ func luaInit() {
hooks = bait.New(l)
hooks.SetRecoverer(func(event string, handler *bait.Listener, err interface{}) {
fmt.Println("Error in", event, "event:", err)
fmt.Println("Error in `error` hook handler:", err)
hooks.Off(event, handler)
})

View File

@ -1,5 +1,6 @@
-- Prelude initializes everything else for our shell
local _ = require 'succulent' -- Function additions
local bait = require 'bait'
local fs = require 'fs'
package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua'
@ -64,3 +65,7 @@ do
package.path = package.path .. ';' .. startSearchPath
end
bait.catch('error', function(event, handler, err)
bait.release(event, handler)
end)