diff options
| author | unwox <me@unwox.com> | 2024-07-23 23:19:46 +0600 |
|---|---|---|
| committer | unwox <me@unwox.com> | 2024-07-23 23:24:14 +0600 |
| commit | cba8ff3896a59598e9f0aa946fd547002ac23aba (patch) | |
| tree | 33fa5edd8f9640bb00e28f75e6bb73910e80c529 /worker.go | |
| parent | 701d73e4a47964ea40100ab2f329ef1dcc0a6f83 (diff) | |
use luna module instead of returning table for lua->go interaction
Diffstat (limited to 'worker.go')
| -rw-r--r-- | worker.go | 183 |
1 files changed, 91 insertions, 92 deletions
@@ -5,6 +5,7 @@ import ( "io" "log" "net/http" + "sync" ) type HTTPRequest struct { @@ -14,11 +15,6 @@ type HTTPRequest struct { result chan *HTTPResponse } -type EvalRequest struct { - code string - result chan error -} - type HTTPResponse struct { Code int Headers map[string]string @@ -26,58 +22,70 @@ type HTTPResponse struct { } type Worker struct { - read chan interface{} lua *Lua - api LuaRef routes map[string]LuaRef started bool + mu sync.Mutex +} + +func HandleHTTPRequest( + queue chan any, + route string, + req *http.Request, +) chan *HTTPResponse { + res := make(chan *HTTPResponse) + queue <- &HTTPRequest{ + request: req, + route: route, + result: res, + } + return res } -func NewWorker(read chan interface{}) *Worker { +func NewWorker() *Worker { return &Worker { - read: read, routes: make(map[string]LuaRef), lua: &Lua{}, } } -func (w *Worker) Start(filename string) error { +func (w *Worker) Start(filename string, module map[string]any) error { + w.mu.Lock() + defer w.mu.Unlock() + 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 - err = w.initRoutes() + defer w.lua.RestoreStackFunc()() + w.initLunaModule(module) + err := w.lua.Require(filename) if err != nil { return err } - + w.started = true return nil } -func (w *Worker) Listen() { - for { - resStack := w.lua.RestoreStackFunc() - r := <- w.read +func (w *Worker) Listen(queue chan any) { + handle := func() { + defer w.lua.RestoreStackFunc()() + r := <- queue switch r.(type) { case *HTTPRequest: r := r.(*HTTPRequest) - // If in debug mode always use handlers from api table - // instead of cached references. Makes it much easier - // to hot-replace route handlers. - if r.debug { - w.lua.PushFromRef(w.api) - w.lua.PushTableItem("routes") - w.lua.PushTableItem(r.route) - } else { - w.lua.PushFromRef(w.routes[r.route]) + if _, ok := w.routes[r.route]; !ok { + r.result <- &HTTPResponse { + Code: 404, + Headers: make(map[string]string), + Body: "not found", + } + log.Println("no corresponding route") + return } + + w.lua.PushFromRef(w.routes[r.route]) w.lua.PushString(r.request.Method) w.lua.PushString(r.request.URL.Path) @@ -95,12 +103,22 @@ func (w *Worker) Listen() { Body: "server error", } log.Println("could not read a request body") - resStack() - continue + return } w.lua.PushString(string(body)) - w.lua.PCall(4, 3) + err = w.lua.PCall(4, 3) + + if err != nil { + r.result <- &HTTPResponse { + Code: 500, + Headers: make(map[string]string), + Body: "server error", + } + log.Println("could not read a request body") + return + } + code := w.lua.ToInt(-3) rbody := w.lua.ToString(-1) @@ -127,81 +145,62 @@ func (w *Worker) Listen() { Body: rbody, } - case *EvalRequest: - r := r.(*EvalRequest) - err := w.lua.LoadString(r.code) - r.result <- err - default: log.Fatal("unknown request") } - - resStack() } -} -func (w *Worker) Request( - route string, - r *http.Request, - debug bool, -) chan *HTTPResponse { - res := make(chan *HTTPResponse) - w.read <- &HTTPRequest{ - request: r, - route: route, - debug: debug, - result: res, + for { + handle() } - return res } -func (w *Worker) Eval(code string) chan error { - res := make(chan error) - w.read <- &EvalRequest{code: code, result: res} - return res +func (w *Worker) Run(code string) error { + w.mu.Lock() + defer w.mu.Unlock() + defer w.lua.RestoreStackFunc()() + return w.lua.LoadString(code) } -func (w *Worker) ListRoutes() []string { - res := []string{} - for route, _ := range w.routes { - res = append(res, route) - } - return res +func (w *Worker) SetRoute(route string, handler LuaRef) { + w.routes[route] = handler } func (w *Worker) Stop() { + w.mu.Lock() + defer w.mu.Unlock() w.lua.Close() } -func (w *Worker) initLunaModule() { - w.lua.CreateTable(1) - w.lua.PushGoFunction(func (l *Lua) int { - l.PushString("Hello, " + l.ToString(-1)) - return 1 - }) - w.lua.SetTableItem("helloFromGo") +func (w *Worker) initLunaModule(module map[string]any) { + var pushTable func(t map[string]any) + pushTable = func (t map[string]any) { + w.lua.CreateTable(len(t)) + for k, v := range t { + switch v.(type) { + case string: + v, _ := v.(string) + w.lua.PushString(v) + case func (l *Lua) int: + v, _ := v.(func (l *Lua) int) + w.lua.PushGoFunction(v) + case int: + v, _ := v.(int) + w.lua.PushNumber(v) + case map[string]any: + v, _ := v.(map[string]any) + pushTable(v) + default: + // FIXME: more details + log.Fatal("unsupported module value type") + } + w.lua.SetTableItem(k) + } + } + pushTable(module) w.lua.SetGlobal("luna") } -func (w *Worker) initRoutes() error { - defer w.lua.RestoreStackFunc()() - w.lua.PushFromRef(w.api) - w.lua.PushTableItem("routes") - if !w.lua.IsTable(-1) { - return errors.New("\"routes\" must be a table") - } - 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 - } - w.lua.Pop(2) - return nil +func (w *Worker) HasSameLua(l *Lua) bool { + return w.lua == l } |
