diff options
| author | unwox <me@unwox.com> | 2024-06-06 16:08:13 +0600 |
|---|---|---|
| committer | unwox <me@unwox.com> | 2024-06-06 16:08:26 +0600 |
| commit | 97a480249e7c8f605efd7a4252449791eabc90a8 (patch) | |
| tree | cdf6cdad3d05cb22681af039cf6a3a6faf10adcb | |
| parent | 6ef4939963e85fa044753598cd8456d48a155d4a (diff) | |
refactor main.go into several files
| -rw-r--r-- | lua.go | 124 | ||||
| -rw-r--r-- | main.go | 259 | ||||
| -rw-r--r-- | worker.go | 144 |
3 files changed, 268 insertions, 259 deletions
@@ -0,0 +1,124 @@ +package main + +/* +#cgo LDFLAGS: -llua +#include <stdlib.h> +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> +*/ +import "C" +import ( + "errors" + "unsafe" +) + +type LuaRef C.longlong +type Lua struct { + l *C.lua_State +} + +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") + } + if !l.IsTable(-1) { + return 0, errors.New("module did not return a table") + } + return l.PopToRef(), nil +} + + +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 +} + +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 +} + +func (l *Lua) StackLen () int { + return int(C.lua_gettop(l.l)) +} + +func (l *Lua) ToString (index int) string { + return C.GoString(C.lua_tolstring(l.l, C.int(index), nil)) +} + +func (l *Lua) ToInt (index int) int { + return int(C.lua_tonumberx(l.l, C.int(index), nil)) +} + +func (l *Lua) PopToRef () LuaRef { + return LuaRef(C.luaL_ref(l.l, C.LUA_REGISTRYINDEX)) +} + +func (l *Lua) Pop (n int) { + C.lua_settop(l.l, C.int(-n - 1)) +} + +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)) + } +} + +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); +} @@ -1,269 +1,10 @@ package main import ( - "errors" "fmt" - "io" "log" "net/http" ) -/* -#cgo LDFLAGS: -llua -#include <stdlib.h> -#include <lua.h> -#include <lualib.h> -#include <lauxlib.h> -*/ -import "C" - -import "unsafe" - -type LuaRef C.longlong -type Lua struct { - l *C.lua_State -} - -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") - } - if !l.IsTable(-1) { - return 0, errors.New("module did not return a table") - } - return l.PopToRef(), nil -} - - -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 -} - -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 -} - -func (l *Lua) StackLen () int { - return int(C.lua_gettop(l.l)) -} - -func (l *Lua) ToString (index int) string { - return C.GoString(C.lua_tolstring(l.l, C.int(index), nil)) -} - -func (l *Lua) ToInt (index int) int { - return int(C.lua_tonumberx(l.l, C.int(index), nil)) -} - -func (l *Lua) PopToRef () LuaRef { - return LuaRef(C.luaL_ref(l.l, C.LUA_REGISTRYINDEX)) -} - -func (l *Lua) Pop (n int) { - C.lua_settop(l.l, C.int(-n - 1)) -} - -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)) - } -} - -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 - Route string - result chan *WorkerResponse -} - -type WorkerResponse struct { - Code int - Headers map[string]string - Body string -} - -type Worker struct { - read chan *WorkerRequest - lua *Lua - api LuaRef - routes map[string]LuaRef - started bool -} - -func NewWorker(read chan *WorkerRequest) *Worker { - return &Worker { - read: read, - routes: make(map[string]LuaRef), - lua: &Lua{}, - } -} - -func (w *Worker) Start (filename string) error { - if w.started { - return errors.New("already started") - } - - w.lua.Start() - api, err := w.lua.Require(filename) - if err != nil { - return err - } - w.api = api - w.initRoutes() - - return nil -} - -func (w *Worker) Listen () { - for { - r := <- w.read - handlerRef := w.routes[r.Route] - w.lua.PushFromRef(handlerRef) - w.lua.PushString(r.Request.Method) - w.lua.PushString(r.Request.URL.Path) - - fh := make(map[string]string) - for k := range r.Request.Header { - fh[k] = r.Request.Header.Get(k) - } - w.lua.PushTable(fh) - - body, err := io.ReadAll(r.Request.Body) - if err != nil { - w.lua.Pop(4); - // TODO: 500 - return - } - w.lua.PushString(string(body)) - - w.lua.PCall(4, 3) - code := w.lua.ToInt(-3) - rbody := w.lua.ToString(-1) - - // parse headers - headers := make(map[string]string) - 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 := 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 := w.lua.ToString(-1) - headers[k] = v - } - w.lua.Pop(2) - - r.result <- &WorkerResponse { - Code: int(code), - Headers: headers, - Body: rbody, - } - } -} - -func (w *Worker) Request (route string, r *http.Request,) chan *WorkerResponse { - res := make(chan *WorkerResponse) - w.read <- &WorkerRequest{ - Request: r, - Route: route, - result: res, - } - return res -} - -func (w *Worker) ListRoutes() []string { - res := []string{} - for route, _ := range w.routes { - res = append(res, route) - } - return res -} - -func (w *Worker) Stop () { - w.lua.Close() -} - -func (w *Worker) initRoutes() { - 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 := w.lua.PopToRef() - // we must not pop the item key from the stack because - // otherwise C.lua_next won't work properly - route := w.lua.ToString(-1) - w.routes[route] = handlerRef - } - // FIXME: pop? -} func main() { rch := make(chan *WorkerRequest, 4096) diff --git a/worker.go b/worker.go new file mode 100644 index 0000000..d125f17 --- /dev/null +++ b/worker.go @@ -0,0 +1,144 @@ +package main + +import ( + "errors" + "io" + "net/http" +) + +type WorkerRequest struct { + Request *http.Request + Route string + result chan *WorkerResponse +} + +type WorkerResponse struct { + Code int + Headers map[string]string + Body string +} + +type Worker struct { + read chan *WorkerRequest + lua *Lua + api LuaRef + routes map[string]LuaRef + started bool +} + +func NewWorker(read chan *WorkerRequest) *Worker { + return &Worker { + read: read, + routes: make(map[string]LuaRef), + lua: &Lua{}, + } +} + +func (w *Worker) Start (filename string) error { + if w.started { + return errors.New("already started") + } + + w.lua.Start() + api, err := w.lua.Require(filename) + if err != nil { + return err + } + w.api = api + w.initRoutes() + + return nil +} + +func (w *Worker) Listen () { + for { + r := <- w.read + handlerRef := w.routes[r.Route] + w.lua.PushFromRef(handlerRef) + w.lua.PushString(r.Request.Method) + w.lua.PushString(r.Request.URL.Path) + + fh := make(map[string]string) + for k := range r.Request.Header { + fh[k] = r.Request.Header.Get(k) + } + w.lua.PushTable(fh) + + body, err := io.ReadAll(r.Request.Body) + if err != nil { + w.lua.Pop(4); + // TODO: 500 + return + } + w.lua.PushString(string(body)) + + w.lua.PCall(4, 3) + code := w.lua.ToInt(-3) + rbody := w.lua.ToString(-1) + + // parse headers + headers := make(map[string]string) + 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 := 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 := w.lua.ToString(-1) + headers[k] = v + } + w.lua.Pop(2) + + r.result <- &WorkerResponse { + Code: int(code), + Headers: headers, + Body: rbody, + } + } +} + +func (w *Worker) Request (route string, r *http.Request,) chan *WorkerResponse { + res := make(chan *WorkerResponse) + w.read <- &WorkerRequest{ + Request: r, + Route: route, + result: res, + } + return res +} + +func (w *Worker) ListRoutes() []string { + res := []string{} + for route, _ := range w.routes { + res = append(res, route) + } + return res +} + +func (w *Worker) Stop () { + w.lua.Close() +} + +func (w *Worker) initRoutes() { + 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 := w.lua.PopToRef() + // we must not pop the item key from the stack because + // otherwise C.lua_next won't work properly + route := w.lua.ToString(-1) + w.routes[route] = handlerRef + } + // FIXME: pop? +} |
