func (lua *LuaExt) exec(reqLogger log.Logger, app *LuaApp, appID, reqId, script string, w http.ResponseWriter, r *http.Request) int { // FIXME(tsileo) a debug mode, with a defer/recover // also parse the Lu error and show the bugging line! start := time.Now() httpClient := &http.Client{} // Initialize internal Lua module written in Go logger := loggerModule.New(reqLogger.New("ctx", "Lua"), start, reqId) response := responseModule.New() request := requestModule.New(r, reqId, lua.authFunc) blobstore := blobstoreModule.New(lua.blobStore) kvstore := kvstoreModule.New(lua.kvStore) bewit := bewitModule.New(reqLogger.New("ctx", "Lua bewit module"), r) template := templateModule.New() // Initialize Lua state L := luamod.NewState() defer L.Close() setCustomGlobals(L) L.PreloadModule("request", request.Loader) L.PreloadModule("response", response.Loader) L.PreloadModule("logger", logger.Loader) L.PreloadModule("blobstore", blobstore.Loader) L.PreloadModule("kvstore", kvstore.Loader) L.PreloadModule("bewit", bewit.Loader) L.PreloadModule("template", template.Loader) // TODO(tsileo) docstore module // TODO(tsileo) cookies module // TODO(tsileo) lru module // TODO(tsileo) cache module => to cache response // TODO(tsileo) load module from github directly? // TODO(tsileo) ETag support // 3rd party module luajson.Preload(L) L.PreloadModule("http", gluahttp.NewHttpModule(httpClient).Loader) // Set some global variables L.SetGlobal("reqID", luamod.LString(reqId)) L.SetGlobal("appID", luamod.LString(appID)) // Execute the code if err := L.DoString(script); err != nil { // FIXME better error, with debug mode? panic(err) } // Apply the Response object to the actual response response.WriteTo(w) // TODO save the logRecords in the AppStats and find a way to serve them over Server-Sent Events // keep them in memory with the ability to dump them in bulk as blob for later query // logRecords := logger.Records() for _, logRecord := range logger.Records() { app.logs = append(app.logs, logRecord) } reqLogger.Info("Script executed", "response", response, "duration", time.Since(start)) return response.Status() }
func setCustomGlobals(L *luamod.LState) { // Return the server unix timestamp L.SetGlobal("unix", L.NewFunction(func(L *luamod.LState) int { L.Push(luamod.LNumber(time.Now().Unix())) return 1 })) // Generate a random hexadecimal ID with the current timestamp as first 4 bytes, // this means keys will be sorted by creation date automatically if sorted lexicographically L.SetGlobal("hexid", L.NewFunction(func(L *luamod.LState) int { id, err := hexid.New(int(time.Now().UTC().Unix())) if err != nil { panic(err) } L.Push(luamod.LString(id.String())) return 1 })) // Compute the Blake2B hash for the given string L.SetGlobal("blake2b", L.NewFunction(func(L *luamod.LState) int { hash := fmt.Sprintf("%x", blake2b.Sum256([]byte(L.ToString(1)))) L.Push(luamod.LString(hash)) return 1 })) // Sleep for the given number of seconds L.SetGlobal("sleep", L.NewFunction(func(L *luamod.LState) int { time.Sleep(time.Duration(float64(L.ToNumber(1)) * float64(1e9))) return 0 })) // Convert the given Markdown to HTML L.SetGlobal("markdownify", L.NewFunction(func(L *luamod.LState) int { output := blackfriday.MarkdownCommon([]byte(L.ToString(1))) L.Push(luamod.LString(string(output))) return 1 })) // Render execute a Go HTML template, data must be a table with string keys L.SetGlobal("render", L.NewFunction(func(L *luamod.LState) int { tplString := L.ToString(1) data := luautil.TableToMap(L.ToTable(2)) tpl, err := template.New("tpl").Parse(tplString) if err != nil { L.Push(luamod.LString(err.Error())) return 1 } // TODO(tsileo) add some templatFuncs/template filter out := &bytes.Buffer{} if err := tpl.Execute(out, data); err != nil { L.Push(luamod.LString(err.Error())) return 1 } L.Push(luamod.LString(out.String())) return 1 })) // TODO(tsileo) a urljoin? // Return an absoulte URL for the given path L.SetGlobal("url", L.NewFunction(func(L *luamod.LState) int { // FIXME(tsileo) take the host from the req? L.Push(luamod.LString("http://localhost:8050" + L.ToString(1))) return 1 })) }