use fasthttp static file serving
This commit is contained in:
parent
e95f0f3370
commit
12ba756b95
@ -4,7 +4,9 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -18,6 +20,8 @@ var (
|
||||
globalStateCreator StateCreator
|
||||
globalMu sync.RWMutex
|
||||
serverRunning bool
|
||||
staticHandlers = make(map[string]*fasthttp.FS)
|
||||
staticMu sync.RWMutex
|
||||
)
|
||||
|
||||
func SetStateCreator(creator StateCreator) {
|
||||
@ -26,11 +30,12 @@ func SetStateCreator(creator StateCreator) {
|
||||
|
||||
func GetFunctionList() map[string]luajit.GoFunction {
|
||||
return map[string]luajit.GoFunction{
|
||||
"http_create_server": http_create_server,
|
||||
"http_spawn_workers": http_spawn_workers,
|
||||
"http_listen": http_listen,
|
||||
"http_close_server": http_close_server,
|
||||
"http_has_servers": http_has_servers,
|
||||
"http_create_server": http_create_server,
|
||||
"http_spawn_workers": http_spawn_workers,
|
||||
"http_listen": http_listen,
|
||||
"http_close_server": http_close_server,
|
||||
"http_has_servers": http_has_servers,
|
||||
"http_register_static": http_register_static,
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,6 +167,32 @@ func http_has_servers(s *luajit.State) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func http_register_static(s *luajit.State) int {
|
||||
if err := s.CheckMinArgs(2); err != nil {
|
||||
return s.PushError("http_register_static: %v", err)
|
||||
}
|
||||
|
||||
urlPrefix := s.ToString(1)
|
||||
rootPath := s.ToString(2)
|
||||
|
||||
// Ensure prefix starts with /
|
||||
if !strings.HasPrefix(urlPrefix, "/") {
|
||||
urlPrefix = "/" + urlPrefix
|
||||
}
|
||||
|
||||
// Convert to absolute path
|
||||
absPath, err := filepath.Abs(rootPath)
|
||||
if err != nil {
|
||||
s.PushBoolean(false)
|
||||
s.PushString(fmt.Sprintf("invalid path: %v", err))
|
||||
return 2
|
||||
}
|
||||
|
||||
RegisterStaticHandler(urlPrefix, absPath)
|
||||
s.PushBoolean(true)
|
||||
return 1
|
||||
}
|
||||
|
||||
func HasActiveServers() bool {
|
||||
globalMu.RLock()
|
||||
defer globalMu.RUnlock()
|
||||
@ -175,6 +206,22 @@ func WaitForServers() {
|
||||
}
|
||||
|
||||
func handleRequest(ctx *fasthttp.RequestCtx) {
|
||||
path := string(ctx.Path())
|
||||
|
||||
// Check static handlers first
|
||||
staticMu.RLock()
|
||||
for prefix, fs := range staticHandlers {
|
||||
if strings.HasPrefix(path, prefix) {
|
||||
staticMu.RUnlock()
|
||||
// Remove prefix and serve
|
||||
ctx.Request.URI().SetPath(strings.TrimPrefix(path, prefix))
|
||||
fs.NewRequestHandler()(ctx)
|
||||
return
|
||||
}
|
||||
}
|
||||
staticMu.RUnlock()
|
||||
|
||||
// Fall back to Lua handling
|
||||
globalMu.RLock()
|
||||
pool := globalWorkerPool
|
||||
globalMu.RUnlock()
|
||||
@ -230,3 +277,19 @@ func handleRequest(ctx *fasthttp.RequestCtx) {
|
||||
ctx.SetBodyString(resp.Body)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterStaticHandler adds a static file handler
|
||||
func RegisterStaticHandler(urlPrefix, rootPath string) {
|
||||
staticMu.Lock()
|
||||
defer staticMu.Unlock()
|
||||
|
||||
fs := &fasthttp.FS{
|
||||
Root: rootPath,
|
||||
IndexNames: []string{"index.html"},
|
||||
GenerateIndexPages: false,
|
||||
Compress: true,
|
||||
AcceptByteRange: true,
|
||||
}
|
||||
|
||||
staticHandlers[urlPrefix] = fs
|
||||
}
|
||||
|
@ -523,48 +523,18 @@ function http.cors(options)
|
||||
end
|
||||
end
|
||||
|
||||
function http.static(root_path)
|
||||
function http.static(root_path, url_prefix)
|
||||
url_prefix = url_prefix or "/"
|
||||
|
||||
if not _G.__IS_WORKER then
|
||||
local success, err = moonshark.http_register_static(url_prefix, root_path)
|
||||
if not success then
|
||||
error("Failed to register static handler: " .. (err or "unknown error"))
|
||||
end
|
||||
end
|
||||
|
||||
-- Return no-op middleware
|
||||
return function(req, res, next)
|
||||
if req.method ~= "GET" and req.method ~= "HEAD" then
|
||||
next()
|
||||
return
|
||||
end
|
||||
|
||||
local file_path = moonshark.path_join(root_path, req.path)
|
||||
file_path = moonshark.path_clean(file_path)
|
||||
|
||||
local abs_root = moonshark.path_abs(root_path)
|
||||
local abs_file = moonshark.path_abs(file_path)
|
||||
|
||||
if not abs_file or not abs_file:find("^" .. abs_root:gsub("([%(%)%.%+%-%*%?%[%]%^%$%%])", "%%%1")) then
|
||||
next()
|
||||
return
|
||||
end
|
||||
|
||||
if moonshark.file_exists(file_path) and not moonshark.file_is_dir(file_path) then
|
||||
local content = moonshark.file_read(file_path)
|
||||
if content then
|
||||
local ext = moonshark.path_ext(file_path):lower()
|
||||
local content_types = {
|
||||
[".html"] = "text/html",
|
||||
[".css"] = "text/css",
|
||||
[".js"] = "application/javascript",
|
||||
[".json"] = "application/json",
|
||||
[".png"] = "image/png",
|
||||
[".jpg"] = "image/jpeg",
|
||||
[".jpeg"] = "image/jpeg",
|
||||
[".gif"] = "image/gif",
|
||||
[".svg"] = "image/svg+xml",
|
||||
[".webp"] = "image/webp",
|
||||
[".txt"] = "text/plain",
|
||||
}
|
||||
|
||||
local content_type = content_types[ext] or "application/octet-stream"
|
||||
res:type(content_type):send(content)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
next()
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user