engine/servelua.go
Rama main · réplica de lectura del repositorio original.
package engine
import (
"fmt"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"github.com/flosch/pongo2/v6"
"github.com/sirupsen/logrus"
"github.com/xyproto/algernon/lua/convert"
"github.com/xyproto/gluamapper"
lua "github.com/xyproto/gopher-lua"
)
// LoadServeFile exposes functions for serving other files to Lua
func (ac *Config) LoadServeFile(w http.ResponseWriter, req *http.Request, L *lua.LState, filename string) {
// Serve a file in the scriptdir
L.SetGlobal("serve", L.NewFunction(func(L *lua.LState) int {
scriptdir := filepath.Dir(filename)
serveFilename := filepath.Join(scriptdir, L.ToString(1))
dataFilename := filepath.Join(scriptdir, defaultLuaDataFilename)
if L.GetTop() >= 2 {
// Optional argument for using a different file than "data.lua"
dataFilename = filepath.Join(scriptdir, L.ToString(2))
}
if !ac.fs.Exists(serveFilename) {
logrus.Error("Could not serve " + serveFilename + ". File not found.")
return 0 // Number of results
}
if ac.fs.IsDir(serveFilename) {
logrus.Error("Could not serve " + serveFilename + ". Not a file.")
return 0 // Number of results
}
ac.FilePage(w, req, serveFilename, dataFilename)
return 0 // Number of results
}))
// Output text as rendered Pongo2, using a po2 file and an optional table
L.SetGlobal("serve2", L.NewFunction(func(L *lua.LState) int {
scriptdir := filepath.Dir(filename)
// Use the first argument as the template and the second argument as the data map
templateFilename := filepath.Join(scriptdir, L.CheckString(1))
ext := filepath.Ext(strings.ToLower(templateFilename))
templateData, err := ac.cache.Read(templateFilename, ac.shouldCache(ext))
if err != nil {
if ac.debugMode {
fmt.Fprintf(w, "Unable to read %s: %s", templateFilename, err)
} else {
logrus.Errorf("Unable to read %s: %s", templateFilename, err)
}
return 0 // number of restuls
}
templateString := templateData.String()
// If a table is given as the second argument, fill pongoMap with keys and values
pongoMap := make(pongo2.Context)
if L.GetTop() == 2 {
luaTable := L.CheckTable(2)
if m, ok := gluamapper.ToGoValue(luaTable, gluamapperOption).(map[string]any); ok {
pongoMap = pongo2.Context(m)
}
} else if L.GetTop() > 2 {
logrus.Error("Too many arguments given to the serve2 function")
return 0 // number of restuls
}
// Retrieve all the function arguments as a bytes.Buffer
buf := convert.Arguments2buffer(L, true)
// Use the buffer as a template.
// Options are "Pretty printing, but without line numbers."
tpl, err := pongo2.FromString(templateString)
if err != nil {
if ac.debugMode {
fmt.Fprint(w, "Could not compile Pongo2 template:\n\t"+err.Error()+"\n\n"+buf.String())
} else {
logrus.Errorf("Could not compile Pongo2 template:\n%s\n%s", err, buf.String())
}
return 0 // number of results
}
// nil is the template context (variables etc in a map)
if err := tpl.ExecuteWriter(pongoMap, w); err != nil {
if ac.debugMode {
fmt.Fprint(w, "Could not compile Pongo2:\n\t"+err.Error()+"\n\n"+buf.String())
} else {
logrus.Errorf("Could not compile Pongo2:\n%s\n%s", err, buf.String())
}
}
return 0 // number of results
}))
// Get the rendered contents of a file in the scriptdir. Discards HTTP headers.
L.SetGlobal("render", L.NewFunction(func(L *lua.LState) int {
scriptdir := filepath.Dir(filename)
serveFilename := filepath.Join(scriptdir, L.ToString(1))
dataFilename := filepath.Join(scriptdir, defaultLuaDataFilename)
if L.GetTop() >= 2 {
// Optional argument for using a different file than "data.lua"
dataFilename = filepath.Join(scriptdir, L.ToString(2))
}
if !ac.fs.Exists(serveFilename) {
logrus.Error("Could not render " + serveFilename + ". File not found.")
return 0 // Number of results
}
if ac.fs.IsDir(serveFilename) {
logrus.Error("Could not render " + serveFilename + ". Not a file.")
return 0 // Number of results
}
// Render the filename to a httptest.Recorder
recorder := httptest.NewRecorder()
ac.FilePage(recorder, req, serveFilename, dataFilename)
s, err := RecorderToString(recorder)
if err != nil {
logrus.Error("RecorderToString: " + err.Error())
return 0 // number of results
}
// Return the recorder as a string
L.Push(lua.LString(s))
return 1 // Number of results
}))
}