diff options
| -rw-r--r-- | main.go | 222 |
1 files changed, 142 insertions, 80 deletions
@@ -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)) } |
