summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lua.go46
-rw-r--r--main.go4
-rw-r--r--worker.go25
3 files changed, 58 insertions, 17 deletions
diff --git a/lua.go b/lua.go
index e7eee54..d7f27fa 100644
--- a/lua.go
+++ b/lua.go
@@ -27,25 +27,30 @@ import (
)
type LuaRef C.longlong
+// Lua is a wrapper around C Lua state with several conveniences.
type Lua struct {
l *C.lua_State
}
//export luna_run_go_func
+// luna_run_go_func calls a Go function from C/Lua.
func luna_run_go_func(f C.uintptr_t) C.int {
fn := cgo.Handle(f).Value().(func() int)
return C.int(fn())
}
+// Start opens the Lua context with all built-in libraries.
func (l *Lua) Start() {
l.l = C.luaL_newstate()
C.luaL_openlibs(l.l)
}
+// Close closes the Lua context.
func (l *Lua) Close() {
C.lua_close(l.l)
}
+// Require loads and executes the file pushing results onto the Lua stack.
func (l *Lua) Require(file string) error {
if !l.LoadFile(file) {
errMsg := l.ToString(-1)
@@ -59,7 +64,8 @@ func (l *Lua) Require(file string) error {
return nil
}
-
+// PCall calls a function with the stack index (-nargs - 1) expecting nresults
+// number of results.
func (l *Lua) PCall(nargs int, nresults int) error {
res := C.lua_pcallk(l.l, C.int(nargs), C.int(nresults), 0, 0, nil)
if res != C.LUA_OK {
@@ -70,6 +76,7 @@ func (l *Lua) PCall(nargs int, nresults int) error {
return nil
}
+// LoadFile loads the file code in the current Lua context.
func (l *Lua) LoadFile(file string) bool {
cstr := C.CString(file)
defer C.free(unsafe.Pointer(cstr))
@@ -77,41 +84,52 @@ func (l *Lua) LoadFile(file string) bool {
return res == C.LUA_OK
}
+// StackLen returns the length of the Lua stack.
func (l *Lua) StackLen() int {
return int(C.lua_gettop(l.l))
}
+// ToInt converts a stack value with stack index -1 into a string.
func (l *Lua) ToString(index int) string {
return C.GoString(C.lua_tolstring(l.l, C.int(index), nil))
}
+// ToInt converts a stack value with stack index -1 into a number.
func (l *Lua) ToInt(index int) int {
return int(C.lua_tonumberx(l.l, C.int(index), nil))
}
+// PopToRef pops the item (stack offset -1) from the stack and then stores it
+// in the registry.
func (l *Lua) PopToRef() LuaRef {
return LuaRef(C.luaL_ref(l.l, C.LUA_REGISTRYINDEX))
}
+// Pop pops N items from the Lua stack.
func (l *Lua) Pop(n int) {
C.lua_settop(l.l, C.int(-n - 1))
}
+// PushNumber pushes tnil onto the Lua stack.
func (l *Lua) PushNil() {
C.lua_pushnil(l.l)
}
+// PushNumber pushes the number onto the Lua stack.
func (l *Lua) PushNumber(num int) {
C.lua_pushnumber(l.l, C.double(num))
}
+// PushString pushes the string onto the Lua stack.
func (l *Lua) PushString(str string) {
cstr := C.CString(str)
defer C.free(unsafe.Pointer(cstr))
C.lua_pushstring(l.l, cstr)
}
-// You may need to delete handle with .Delete() method later.
+// PushGoFunction pushes a Go function onto the Lua stack so it's possible to
+// call it from Lua. You may need to delete returned handle with .Delete()
+// method later.
func (l *Lua) PushGoFunction(f func (l *Lua) int) cgo.Handle {
h := cgo.NewHandle(func () int {
return f(l)
@@ -120,17 +138,20 @@ func (l *Lua) PushGoFunction(f func (l *Lua) int) cgo.Handle {
return h
}
-// CreateTable pushes a new table onto the stack.
+// CreateTable pushes a new Lua table onto the stack.
func (l *Lua) CreateTable(len int) {
C.lua_createtable(l.l, 0, C.int(len))
}
+// SetTableItem adds a value (stack offset -1) to a table (offset -2) under
+// the specified key.
func (l *Lua) SetTableItem(key string) {
cstr := C.CString(key)
defer C.free(unsafe.Pointer(cstr))
C.lua_setfield(l.l, -2, C.CString(key))
}
+// PushStringTable pushes string->string table onto the stack.
func (l *Lua) PushStringTable(table map[string]string) {
l.CreateTable(len(table))
for k, v := range table {
@@ -139,37 +160,38 @@ func (l *Lua) PushStringTable(table map[string]string) {
}
}
+// PushFromRef pushes a value from registry ref onto the stack.
func (l *Lua) PushFromRef(ref LuaRef) {
C.lua_rawgeti(l.l, C.LUA_REGISTRYINDEX, C.longlong(ref));
}
-func (l *Lua) PushTableItem(key string) {
- ckey := C.CString(key)
- defer C.free(unsafe.Pointer(ckey))
- C.lua_pushstring(l.l, ckey);
- C.lua_gettable(l.l, -2);
-}
-
+// IsString checks if the stack contains a string under the given index.
func (l *Lua) IsString(index int) bool {
return C.lua_isstring(l.l, C.int(index)) == 1
}
+// IsNumber checks if the stack contains a number (both int and float) under
+// the given index.
func (l *Lua) IsNumber(index int) bool {
return C.lua_isnumber(l.l, C.int(index)) == 1
}
+// IsFunction checks if the stack contains a function under the given index.
func (l *Lua) IsFunction(index int) bool {
return C.lua_type(l.l, C.int(index)) == C.LUA_TFUNCTION
}
+// IsTable checks if the stack contains a table under the given index.
func (l *Lua) IsTable(index int) bool {
return C.lua_type(l.l, C.int(index)) == C.LUA_TTABLE
}
+// Next advances a table iterator at the stack index -2.
func (l *Lua) Next() bool {
return C.lua_next(l.l, -2) != 0
}
+// LoadString loads and executes the code in the current Lua context.
func (l *Lua) LoadString(code string) error {
cstr := C.CString(code)
defer C.free(unsafe.Pointer(cstr))
@@ -186,6 +208,8 @@ func (l *Lua) LoadString(code string) error {
return nil
}
+// RestoreStackFunc remembers the Lua stack size and then restores it when a
+// returned function is called. It's a helper function to avoid stack leakage.
func (l *Lua) RestoreStackFunc() func () {
before := l.StackLen()
return func () {
@@ -205,12 +229,14 @@ func (l *Lua) RestoreStackFunc() func () {
}
}
+// SetGlobal sets a global value at the -1 stack index with the name.
func (l *Lua) SetGlobal(name string) {
cstr := C.CString(name)
defer C.free(unsafe.Pointer(cstr))
C.lua_setglobal(l.l, cstr)
}
+// GetGlobal gets a global value under the name.
func (l *Lua) GetGlobal(name string) {
cstr := C.CString(name)
defer C.free(unsafe.Pointer(cstr))
diff --git a/main.go b/main.go
index 8fb3608..5a876b9 100644
--- a/main.go
+++ b/main.go
@@ -10,9 +10,11 @@ import (
)
func main() {
+ // queue for http messages for workers to handle
msgs := make(chan interface{}, 4096)
mux := http.NewServeMux()
wrks := []*Worker{}
+ // track routes for mux to avoid registering the same route twice
routes := make(map[string]bool)
// define luna.router module
@@ -85,7 +87,7 @@ func main() {
for {
code, _ := reader.ReadString('\n')
for _, wrk := range wrks {
- if err := wrk.Run(code); err != nil {
+ if err := wrk.Eval(code); err != nil {
log.Printf("error: %s\n", err)
break
}
diff --git a/worker.go b/worker.go
index b79f7e8..5d6eeb1 100644
--- a/worker.go
+++ b/worker.go
@@ -42,6 +42,7 @@ func HandleHTTPRequest(
return res
}
+// NewWorker creates a new instance of Worker type.
func NewWorker() *Worker {
return &Worker {
routes: make(map[string]LuaRef),
@@ -49,6 +50,11 @@ func NewWorker() *Worker {
}
}
+// Start starts the worker:
+// 1) creates a Lua context
+// 2) executes the filename in it
+// 3) initiates the the "luna" module so it's possible to call Go functions
+// from Lua
func (w *Worker) Start(filename string, module map[string]any) error {
w.mu.Lock()
defer w.mu.Unlock()
@@ -67,6 +73,7 @@ func (w *Worker) Start(filename string, module map[string]any) error {
return nil
}
+// Listen starts a goroutine listening/handling HTTP requests from the queue.
func (w *Worker) Listen(queue chan any) {
handle := func() {
defer w.lua.RestoreStackFunc()()
@@ -155,23 +162,33 @@ func (w *Worker) Listen(queue chan any) {
}
}
-func (w *Worker) Run(code string) error {
+// Eval evaluates the code in the Lua context.
+func (w *Worker) Eval(code string) error {
w.mu.Lock()
defer w.mu.Unlock()
defer w.lua.RestoreStackFunc()()
return w.lua.LoadString(code)
}
+// SetRoute sets a handler for the route.
func (w *Worker) SetRoute(route string, handler LuaRef) {
w.routes[route] = handler
}
+// Stop stops the worker closing the Lua context. TODO: stop Listen goroutine
+// as well.
func (w *Worker) Stop() {
w.mu.Lock()
defer w.mu.Unlock()
w.lua.Close()
}
+// HasSameLua checks if the Lua context belongs to the worker.
+func (w *Worker) HasSameLua(l *Lua) bool {
+ return w.lua == l
+}
+
+// initLunaModule registers the module in the Lua context.
func (w *Worker) initLunaModule(module map[string]any) {
var pushTable func(t map[string]any)
pushTable = func (t map[string]any) {
@@ -191,7 +208,7 @@ func (w *Worker) initLunaModule(module map[string]any) {
v, _ := v.(map[string]any)
pushTable(v)
default:
- // FIXME: more details
+ // FIXME: more details.
log.Fatal("unsupported module value type")
}
w.lua.SetTableItem(k)
@@ -200,7 +217,3 @@ func (w *Worker) initLunaModule(module map[string]any) {
pushTable(module)
w.lua.SetGlobal("luna")
}
-
-func (w *Worker) HasSameLua(l *Lua) bool {
- return w.lua == l
-}