mirror of
https://github.com/jhillyerd/inbucket.git
synced 2026-01-08 20:21:55 +00:00
lua: Init with config and pool (#321)
* lua: Intial impl with config and pool Signed-off-by: James Hillyerd <james@hillyerd.com>
This commit is contained in:
91
pkg/extension/luahost/pool.go
Normal file
91
pkg/extension/luahost/pool.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package luahost
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
)
|
||||
|
||||
type statePool struct {
|
||||
sync.Mutex
|
||||
funcProto *lua.FunctionProto // Compiled lua.
|
||||
states []*lua.LState // Pool of available LStates.
|
||||
channels map[string]chan lua.LValue // Global interop channels.
|
||||
}
|
||||
|
||||
func newStatePool(funcProto *lua.FunctionProto) *statePool {
|
||||
return &statePool{
|
||||
funcProto: funcProto,
|
||||
channels: make(map[string]chan lua.LValue),
|
||||
}
|
||||
}
|
||||
|
||||
// newState creates a new LState and configures it. Lock must be held.
|
||||
func (lp *statePool) newState() (*lua.LState, error) {
|
||||
ls := lua.NewState()
|
||||
|
||||
// Setup channels.
|
||||
for name, ch := range lp.channels {
|
||||
ls.SetGlobal(name, lua.LChannel(ch))
|
||||
}
|
||||
|
||||
// Run compiled script.
|
||||
ls.Push(ls.NewFunctionFromProto(lp.funcProto))
|
||||
if err := ls.PCall(0, lua.MultRet, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ls, nil
|
||||
}
|
||||
|
||||
// getState returns a free LState, or creates a new one.
|
||||
func (lp *statePool) getState() (*lua.LState, error) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
ln := len(lp.states)
|
||||
if ln == 0 {
|
||||
return lp.newState()
|
||||
}
|
||||
|
||||
state := lp.states[ln-1]
|
||||
lp.states = lp.states[0 : ln-1]
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// putState returns the LState to the pool.
|
||||
func (lp *statePool) putState(state *lua.LState) {
|
||||
if state.IsClosed() {
|
||||
return
|
||||
}
|
||||
|
||||
// Clear stack.
|
||||
state.Pop(state.GetTop())
|
||||
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
lp.states = append(lp.states, state)
|
||||
}
|
||||
|
||||
// createChannel creates a new channel, which will become a global variable in
|
||||
// newly created LStates. We also destroy any pooled states.
|
||||
//
|
||||
// Warning: There may still be checked out LStates that will not have the value
|
||||
// set, which could be put back into the pool.
|
||||
func (lp *statePool) createChannel(name string) chan lua.LValue {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
ch := make(chan lua.LValue, 10)
|
||||
lp.channels[name] = ch
|
||||
|
||||
// Flush state pool.
|
||||
for _, s := range lp.states {
|
||||
s.Close()
|
||||
}
|
||||
lp.states = lp.states[:0]
|
||||
|
||||
return ch
|
||||
}
|
||||
Reference in New Issue
Block a user