summaryrefslogtreecommitdiff
path: root/worker.go
diff options
context:
space:
mode:
Diffstat (limited to 'worker.go')
-rw-r--r--worker.go144
1 files changed, 144 insertions, 0 deletions
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?
+}