package server import ( "fes/modules/config" "io/fs" "path/filepath" "strings" lua "github.com/yuin/gopher-lua" ) type reqData struct { path string params map[string]string } func render(luapath string, requestData reqData, protocol Protocols) ([]byte, error) { L := lua.NewState() defer L.Close() if lib, err := fs.ReadDir(config.Lib, "lib"); err == nil { for _, de := range lib { if de.IsDir() || !strings.HasSuffix(de.Name(), ".lua") { continue } path := filepath.Join("lib", de.Name()) if data, err := config.Lib.ReadFile(path); err == nil { _ = L.DoString(string(data)) } } } preloadLuaModule := func(name, path string) { L.PreloadModule(name, func(L *lua.LState) int { fileData, err := config.Lib.ReadFile(path) if err != nil { panic(err) } if err := L.DoString(string(fileData)); err != nil { panic(err) } return 1 }) } preloadLuaModule("lib.std", "lib/std.lua") preloadLuaModule("lib.symbol", "lib/symbol.lua") preloadLuaModule("lib.util", "lib/util.lua") L.PreloadModule("fes", func(L *lua.LState) int { fileData, err := config.Lib.ReadFile("lib/fes.lua") if err != nil { panic(err) } if err := L.DoString(string(fileData)); err != nil { panic(err) } mod := L.Get(-1) L.Pop(1) tbl, ok := mod.(*lua.LTable) if !ok { panic("fes module did not return table") } if err := L.CallByParam(lua.P{ Fn: L.GetGlobal("require"), NRet: 1, Protect: true, }, lua.LString("lib.std")); err != nil { panic(err) } stdMod := L.Get(-1) L.Pop(1) stdTbl, ok := stdMod.(*lua.LTable) if !ok { panic("lib.std did not return table") } proto := func() string { switch protocol { case HTTP: return "http" case GEMINI: return "gemini" default: return "http" } }() proto = "gemini" stdTbl.RawSetString("proto", lua.LString(proto)) tbl.RawSetString("std", stdTbl) bus := L.NewTable() bus.RawSetString("url", lua.LString(requestData.path)) params := L.NewTable() for k, v := range requestData.params { params.RawSetString(k, lua.LString(v)) } bus.RawSetString("params", params) tbl.RawSetString("bus", bus) tbl.RawSetString("markdown_to_html", L.NewFunction(func(L *lua.LState) int { L.Push(lua.LString(markdownToHTML(L.ToString(1)))) return 1 })) L.Push(tbl) return 1 }) if err := L.DoFile(luapath); err != nil { return []byte(""), err } if L.GetTop() == 0 { return []byte(""), nil } val := L.Get(-1) L.Pop(1) if val == lua.LNil { return []byte(""), nil } if err := L.CallByParam(lua.P{ Fn: L.GetGlobal("tostring"), NRet: 1, Protect: true, }, val); err != nil { return nil, err } s := L.ToString(-1) L.Pop(1) if s != "" { return []byte(s), nil } return []byte(""), nil }