summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lua.go124
-rw-r--r--main.go259
-rw-r--r--worker.go144
3 files changed, 268 insertions, 259 deletions
diff --git a/lua.go b/lua.go
new file mode 100644
index 0000000..874dac8
--- /dev/null
+++ b/lua.go
@@ -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);
+}
diff --git a/main.go b/main.go
index 12c0248..ccacca3 100644
--- a/main.go
+++ b/main.go
@@ -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?
+}