summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunwox <me@unwox.com>2024-06-06 15:22:43 +0600
committerunwox <me@unwox.com>2024-06-06 16:00:43 +0600
commit6ef4939963e85fa044753598cd8456d48a155d4a (patch)
tree05ce080e4f50d169af55a12ac667fbdb94805eda
parent2012809dc4a4692456d811c9b3f0293c54f4320b (diff)
a better lua integration
-rw-r--r--main.go222
1 files changed, 142 insertions, 80 deletions
diff --git a/main.go b/main.go
index 01027e7..12c0248 100644
--- a/main.go
+++ b/main.go
@@ -9,68 +9,124 @@ import (
)
/*
#cgo LDFLAGS: -llua
+#include <stdlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
+*/
+import "C"
-int
-luna_load_file(lua_State *L, char *file) {
- if (luaL_dofile(L, file) != LUA_OK) {
- return -1;
- }
- if (!lua_istable(L, -1)) {
+import "unsafe"
+
+type LuaRef C.longlong
+type Lua struct {
+ l *C.lua_State
+}
- return -1;
+func (l *Lua) Start () {
+ l.l = C.luaL_newstate()
+ C.luaL_openlibs(l.l)
+}
+
+func (l *Lua) Close () {
+ C.lua_close(l.l)
+ C.free(unsafe.Pointer(l.l))
+}
+
+func (l *Lua) Require (file string) (LuaRef, error) {
+ if !l.LoadFile(file) {
+ return 0, errors.New("could not open the file")
+ }
+ if !l.PCall(0, C.LUA_MULTRET) {
+ return 0, errors.New("could not execute the file")
}
- return luaL_ref(L, LUA_REGISTRYINDEX);
+ if !l.IsTable(-1) {
+ return 0, errors.New("module did not return a table")
+ }
+ return l.PopToRef(), nil
}
-int
-luna_isfunction(lua_State *L, int n) {
- return lua_isfunction(L, n);
+
+func (l *Lua) PCall (nargs int, nresults int) bool {
+ res := C.lua_pcallk(l.l, C.int(nargs), C.int(nresults), 0, 0, nil)
+ return res == C.LUA_OK
}
-void
-luna_push_table_item(lua_State *L, int ref, char *key) {
- lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
- lua_pushstring(L, key);
- lua_gettable(L, -2);
+func (l *Lua) LoadFile (file string) bool {
+ cfile := C.CString(file)
+ defer C.free(unsafe.Pointer(cfile))
+ res := C.luaL_loadfilex(l.l, cfile, nil)
+ return res == C.LUA_OK
}
-void
-luna_pop(lua_State *L, int n) {
- lua_pop(L, n);
+func (l *Lua) StackLen () int {
+ return int(C.lua_gettop(l.l))
}
-const char *
-luna_tostring(lua_State *L, int n) {
- return lua_tostring(L, n);
+func (l *Lua) ToString (index int) string {
+ return C.GoString(C.lua_tolstring(l.l, C.int(index), nil))
}
-int
-luna_tonumber(lua_State *L, int n) {
- return lua_tonumber(L, n);
+func (l *Lua) ToInt (index int) int {
+ return int(C.lua_tonumberx(l.l, C.int(index), nil))
}
-void
-luna_push_ref(lua_State *L, int ref) {
- lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
+func (l *Lua) PopToRef () LuaRef {
+ return LuaRef(C.luaL_ref(l.l, C.LUA_REGISTRYINDEX))
}
-int
-luna_pop_ref(lua_State *L) {
- return luaL_ref(L, LUA_REGISTRYINDEX);
+func (l *Lua) Pop (n int) {
+ C.lua_settop(l.l, C.int(-n - 1))
}
-const char *
-luna_pcall(lua_State *L, int nargs, int nresults) {
- if (lua_pcall(L, nargs, nresults, 0) != LUA_OK) {
- // FIXME: check for errors
- return NULL;
+func (l *Lua) PushNil () {
+ C.lua_pushnil(l.l)
+}
+
+func (l *Lua) PushString (str string) {
+ cstr := C.CString(str)
+ defer C.free(unsafe.Pointer(cstr))
+ C.lua_pushstring(l.l, cstr)
+}
+
+func (l *Lua) PushTable (table map[string]string) {
+ C.lua_createtable(l.l, 0, C.int(len(table)))
+ for k, v := range table {
+ l.PushString(v)
+ C.lua_setfield(l.l, -2, C.CString(k))
}
}
-*/
-import "C"
+
+func (l *Lua) PushFromRef (ref LuaRef) {
+ C.lua_rawgeti(l.l, C.LUA_REGISTRYINDEX, C.longlong(ref));
+}
+
+func (l *Lua) IsString (index int) bool {
+ return C.lua_isstring(l.l, C.int(index)) == 1
+}
+
+func (l *Lua) IsNumber (index int) bool {
+ return C.lua_isnumber(l.l, C.int(index)) == 1
+}
+
+func (l *Lua) IsFunction (index int) bool {
+ return C.lua_type(l.l, C.int(index)) == C.LUA_TFUNCTION
+}
+
+func (l *Lua) IsTable (index int) bool {
+ return C.lua_type(l.l, C.int(index)) == C.LUA_TTABLE
+}
+
+func (l *Lua) Next () bool {
+ return C.lua_next(l.l, -2) != 0
+}
+
+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);
+}
type WorkerRequest struct {
Request *http.Request
@@ -86,16 +142,17 @@ type WorkerResponse struct {
type Worker struct {
read chan *WorkerRequest
- L *C.lua_State
- routes map[string]C.int
- api C.int
+ lua *Lua
+ api LuaRef
+ routes map[string]LuaRef
started bool
}
func NewWorker(read chan *WorkerRequest) *Worker {
return &Worker {
read: read,
- routes: make(map[string]C.int),
+ routes: make(map[string]LuaRef),
+ lua: &Lua{},
}
}
@@ -104,10 +161,12 @@ func (w *Worker) Start (filename string) error {
return errors.New("already started")
}
- w.L = C.luaL_newstate()
- C.luaL_openlibs(w.L)
- // FIXME: C.luna_load_file should return an error.
- w.api = C.luna_load_file(w.L, C.CString(filename))
+ w.lua.Start()
+ api, err := w.lua.Require(filename)
+ if err != nil {
+ return err
+ }
+ w.api = api
w.initRoutes()
return nil
@@ -117,48 +176,45 @@ func (w *Worker) Listen () {
for {
r := <- w.read
handlerRef := w.routes[r.Route]
- C.luna_push_ref(w.L, handlerRef)
- C.lua_pushstring(w.L, C.CString(r.Request.Method))
- C.lua_pushstring(w.L, C.CString(r.Request.URL.Path))
+ w.lua.PushFromRef(handlerRef)
+ w.lua.PushString(r.Request.Method)
+ w.lua.PushString(r.Request.URL.Path)
- // table for headers
- C.lua_createtable(w.L, 0, C.int(len(r.Request.Header)))
-
+ fh := make(map[string]string)
for k := range r.Request.Header {
- h := r.Request.Header.Get(k)
- C.lua_pushstring(w.L, C.CString(h))
- C.lua_setfield(w.L, -2, C.CString(k))
+ fh[k] = r.Request.Header.Get(k)
}
-
+ w.lua.PushTable(fh)
+
body, err := io.ReadAll(r.Request.Body)
if err != nil {
- C.luna_pop(w.L, 4);
+ w.lua.Pop(4);
// TODO: 500
return
}
+ w.lua.PushString(string(body))
- C.lua_pushstring(w.L, C.CString(string(body)))
- C.luna_pcall(w.L, 4, 3)
- code := C.luna_tonumber(w.L, -3)
- rbody := C.GoString(C.luna_tostring(w.L, -1))
+ w.lua.PCall(4, 3)
+ code := w.lua.ToInt(-3)
+ rbody := w.lua.ToString(-1)
// parse headers
headers := make(map[string]string)
- C.luna_pop(w.L, 1)
- C.lua_pushnil(w.L)
- for C.lua_next(w.L, -2) != 0 {
- if C.lua_isstring(w.L, -2) == 0 || C.lua_isstring(w.L, -1) == 0 {
- C.luna_pop(w.L, 1)
+ w.lua.Pop(1)
+ w.lua.PushNil()
+ for w.lua.Next() {
+ if !w.lua.IsString(-2) || !w.lua.IsString(-2) {
+ w.lua.Pop(1)
continue
}
- v := C.GoString(C.luna_tostring(w.L, -1))
- C.luna_pop(w.L, 1)
+ v := w.lua.ToString(-1)
+ w.lua.Pop(1)
// we must not pop the item key from the stack because
// otherwise C.lua_next won't work properly
- k := C.GoString(C.luna_tostring(w.L, -1))
+ k := w.lua.ToString(-1)
headers[k] = v
}
- C.luna_pop(w.L, 2)
+ w.lua.Pop(2)
r.result <- &WorkerResponse {
Code: int(code),
@@ -187,23 +243,26 @@ func (w *Worker) ListRoutes() []string {
}
func (w *Worker) Stop () {
- C.lua_close(w.L)
+ w.lua.Close()
}
func (w *Worker) initRoutes() {
- C.luna_push_table_item(w.L, w.api, C.CString("routes"))
- C.lua_pushnil(w.L)
- for C.lua_next(w.L, -2) != 0 {
- if C.lua_isstring(w.L, -2) == 0 || C.luna_isfunction(w.L, -1) == 0 {
- C.luna_pop(w.L, 1)
+ w.lua.PushFromRef(w.api)
+ w.lua.PushTableItem("routes")
+ // FIXME: istable?
+ w.lua.PushNil()
+ for w.lua.Next() {
+ if !w.lua.IsString(-2) || !w.lua.IsFunction(-1) {
+ w.lua.Pop(1)
continue
}
- handlerRef := C.luna_pop_ref(w.L)
+ handlerRef := w.lua.PopToRef()
// we must not pop the item key from the stack because
// otherwise C.lua_next won't work properly
- route := C.GoString(C.luna_tostring(w.L, -1))
+ route := w.lua.ToString(-1)
w.routes[route] = handlerRef
}
+ // FIXME: pop?
}
func main() {
@@ -211,7 +270,10 @@ func main() {
for i := 0; i < 8; i++ {
log.Printf("worker %d started\n", i)
w := NewWorker(rch)
- w.Start("init.lua")
+ err := w.Start("init.lua")
+ if err != nil {
+ log.Fatal(err)
+ }
if i == 0 {
for _, route := range w.ListRoutes() {
http.HandleFunc(
@@ -232,5 +294,5 @@ func main() {
defer w.Stop()
}
fmt.Println("running")
- log.Fatal(http.ListenAndServe("127.0.0.1:3001", nil))
+ log.Fatal(http.ListenAndServe("127.0.0.1:3002", nil))
}