luahandler.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package engine
  2. import (
  3. "net/http"
  4. "path/filepath"
  5. "sync"
  6. "github.com/didip/tollbooth"
  7. log "github.com/sirupsen/logrus"
  8. "github.com/xyproto/algernon/themes"
  9. lua "github.com/xyproto/gopher-lua"
  10. )
  11. // LoadLuaHandlerFunctions makes functions related to handling HTTP requests
  12. // available to Lua scripts
  13. func (ac *Config) LoadLuaHandlerFunctions(L *lua.LState, filename string, mux *http.ServeMux, addDomain bool, httpStatus *FutureStatus, theme string) {
  14. luahandlermutex := &sync.RWMutex{}
  15. L.SetGlobal("handle", L.NewFunction(func(L *lua.LState) int {
  16. handlePath := L.ToString(1)
  17. handleFunc := L.ToFunction(2)
  18. // TODO: Set up a channel and function for retrieving a lua "handleFunc" and running it,
  19. // using the common luapool as needed
  20. wrappedHandleFunc := func(w http.ResponseWriter, req *http.Request) {
  21. // Set up a new Lua state with the current http.ResponseWriter and *http.Request
  22. luahandlermutex.Lock()
  23. ac.LoadCommonFunctions(w, req, filename, L, nil, httpStatus)
  24. luahandlermutex.Unlock()
  25. // Then run the given Lua function
  26. L.Push(handleFunc)
  27. if err := L.PCall(0, lua.MultRet, nil); err != nil {
  28. // Non-fatal error
  29. log.Error("Handler for "+handlePath+" failed:", err)
  30. }
  31. // Then exit after the first request, if specified
  32. if ac.quitAfterFirstRequest {
  33. go ac.quitSoon("Quit after first request", defaultSoonDuration)
  34. }
  35. }
  36. // Handle requests differently depending on if rate limiting is enabled or not
  37. if ac.disableRateLimiting {
  38. mux.HandleFunc(handlePath, wrappedHandleFunc)
  39. } else {
  40. limiter := tollbooth.NewLimiter(float64(ac.limitRequests), nil)
  41. limiter.SetMessage(themes.MessagePage("Rate-limit exceeded", "<div style='color:red'>You have reached the maximum request limit.</div>", theme))
  42. limiter.SetMessageContentType("text/html;charset=utf-8")
  43. mux.Handle(handlePath, tollbooth.LimitFuncHandler(limiter, wrappedHandleFunc))
  44. }
  45. return 0 // number of results
  46. }))
  47. L.SetGlobal("servedir", L.NewFunction(func(L *lua.LState) int {
  48. handlePath := L.ToString(1) // serve as (ie. "/")
  49. rootdir := L.ToString(2) // filesystem directory (ie. "./public")
  50. if handlePath == "" || rootdir == "" {
  51. log.Errorf("servedir needs an URL path to serve, ie. %q and a directory releative to %q, ie. %q", "/", filepath.Dir(filename), "./public")
  52. return 0
  53. }
  54. rootdir = filepath.Join(filepath.Dir(filename), rootdir)
  55. ac.RegisterHandlers(mux, handlePath, rootdir, addDomain)
  56. return 0 // number of results
  57. }))
  58. }