177 lines
4.3 KiB
Go
177 lines
4.3 KiB
Go
package router
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// compileWithMiddleware combines middleware and handler source, then compiles
|
|
func (r *LuaRouter) compileWithMiddleware(n *node, fsPath, scriptPath string) error {
|
|
if scriptPath == "" {
|
|
return nil
|
|
}
|
|
|
|
// Check if we need to recompile by comparing modification times
|
|
sourceKey := r.getSourceCacheKey(fsPath, scriptPath)
|
|
needsRecompile := false
|
|
|
|
// Check handler modification time
|
|
handlerInfo, err := os.Stat(scriptPath)
|
|
if err != nil {
|
|
n.err = err
|
|
return err
|
|
}
|
|
|
|
lastCompiled, exists := r.sourceMtimes[sourceKey]
|
|
if !exists || handlerInfo.ModTime().After(lastCompiled) {
|
|
needsRecompile = true
|
|
}
|
|
|
|
// Check middleware modification times
|
|
if !needsRecompile {
|
|
middlewareChain := r.getMiddlewareChain(fsPath)
|
|
for _, mwPath := range middlewareChain {
|
|
mwInfo, err := os.Stat(mwPath)
|
|
if err != nil {
|
|
n.err = err
|
|
return err
|
|
}
|
|
if mwInfo.ModTime().After(lastCompiled) {
|
|
needsRecompile = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use cached bytecode if available and fresh
|
|
if !needsRecompile {
|
|
if bytecode, exists := r.sourceCache[sourceKey]; exists {
|
|
bytecodeKey := getBytecodeKey(scriptPath)
|
|
r.bytecodeCache.Set(bytecodeKey, bytecode)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Build combined source
|
|
combinedSource, err := r.buildCombinedSource(fsPath, scriptPath)
|
|
if err != nil {
|
|
n.err = err
|
|
return err
|
|
}
|
|
|
|
// Compile combined source using shared state
|
|
r.compileStateMu.Lock()
|
|
bytecode, err := r.compileState.CompileBytecode(combinedSource, scriptPath)
|
|
r.compileStateMu.Unlock()
|
|
|
|
if err != nil {
|
|
n.err = err
|
|
return err
|
|
}
|
|
|
|
// Cache everything
|
|
bytecodeKey := getBytecodeKey(scriptPath)
|
|
r.bytecodeCache.Set(bytecodeKey, bytecode)
|
|
r.sourceCache[sourceKey] = bytecode
|
|
r.sourceMtimes[sourceKey] = time.Now()
|
|
|
|
n.err = nil
|
|
return nil
|
|
}
|
|
|
|
// buildCombinedSource builds the combined middleware + handler source
|
|
func (r *LuaRouter) buildCombinedSource(fsPath, scriptPath string) (string, error) {
|
|
var combinedSource strings.Builder
|
|
|
|
// Get middleware chain using filesystem path
|
|
middlewareChain := r.getMiddlewareChain(fsPath)
|
|
|
|
// Add middleware in order
|
|
for _, mwPath := range middlewareChain {
|
|
content, err := r.getFileContent(mwPath)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
combinedSource.WriteString("-- Middleware: ")
|
|
combinedSource.WriteString(mwPath)
|
|
combinedSource.WriteString("\n")
|
|
combinedSource.Write(content)
|
|
combinedSource.WriteString("\n")
|
|
}
|
|
|
|
// Add main handler
|
|
content, err := r.getFileContent(scriptPath)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
combinedSource.WriteString("-- Handler: ")
|
|
combinedSource.WriteString(scriptPath)
|
|
combinedSource.WriteString("\n")
|
|
combinedSource.Write(content)
|
|
|
|
return combinedSource.String(), nil
|
|
}
|
|
|
|
// getFileContent reads file content with caching
|
|
func (r *LuaRouter) getFileContent(path string) ([]byte, error) {
|
|
// Check cache first
|
|
if content, exists := r.middlewareCache[path]; exists {
|
|
// Verify file hasn't changed
|
|
info, err := os.Stat(path)
|
|
if err == nil {
|
|
if cachedTime, exists := r.sourceMtimes[path]; exists && !info.ModTime().After(cachedTime) {
|
|
return content, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read from disk
|
|
content, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Cache it
|
|
r.middlewareCache[path] = content
|
|
r.sourceMtimes[path] = time.Now()
|
|
|
|
return content, nil
|
|
}
|
|
|
|
// getSourceCacheKey generates a unique key for combined source
|
|
func (r *LuaRouter) getSourceCacheKey(fsPath, scriptPath string) string {
|
|
middlewareChain := r.getMiddlewareChain(fsPath)
|
|
var keyParts []string
|
|
keyParts = append(keyParts, middlewareChain...)
|
|
keyParts = append(keyParts, scriptPath)
|
|
return strings.Join(keyParts, "|")
|
|
}
|
|
|
|
// getMiddlewareChain returns middleware files that apply to the given filesystem path
|
|
func (r *LuaRouter) getMiddlewareChain(fsPath string) []string {
|
|
var chain []string
|
|
|
|
// Collect middleware from root to specific path using filesystem path (includes groups)
|
|
pathParts := strings.Split(strings.Trim(fsPath, "/"), "/")
|
|
if pathParts[0] == "" {
|
|
pathParts = []string{}
|
|
}
|
|
|
|
// Add root middleware
|
|
if mw, exists := r.middlewareFiles["/"]; exists {
|
|
chain = append(chain, mw...)
|
|
}
|
|
|
|
// Add middleware from each path level (including groups)
|
|
currentPath := ""
|
|
for _, part := range pathParts {
|
|
currentPath += "/" + part
|
|
if mw, exists := r.middlewareFiles[currentPath]; exists {
|
|
chain = append(chain, mw...)
|
|
}
|
|
}
|
|
|
|
return chain
|
|
}
|