diff --git a/routers/luaRouter.go b/routers/luaRouter.go index 96cb7be..cd6de66 100644 --- a/routers/luaRouter.go +++ b/routers/luaRouter.go @@ -51,7 +51,7 @@ type LuaRouter struct { bytecodeCache *fastcache.Cache // Cache for compiled bytecode // Middleware tracking for path hierarchy - middlewareFiles map[string][]string // path -> middleware file paths + middlewareFiles map[string][]string // filesystem path -> middleware file paths // New caching fields middlewareCache map[string][]byte // path -> content @@ -72,6 +72,40 @@ type node struct { paramChild *node // Parameter/wildcard child err error // Compilation error if any modTime time.Time // Last modification time + fsPath string // Original filesystem path (includes groups) +} + +// pathInfo holds both filesystem and URL path information +type pathInfo struct { + fsPath string // Filesystem path (includes groups) + urlPath string // URL path (excludes groups) +} + +// parsePathWithGroups separates filesystem path from URL path +func parsePathWithGroups(fsPath string) pathInfo { + segments := strings.Split(strings.Trim(fsPath, "/"), "/") + var urlSegments []string + + for _, segment := range segments { + if segment == "" { + continue + } + // Skip group segments for URL path + if len(segment) >= 3 && segment[0] == '(' && segment[len(segment)-1] == ')' { + continue + } + urlSegments = append(urlSegments, segment) + } + + urlPath := "/" + if len(urlSegments) > 0 { + urlPath = "/" + strings.Join(urlSegments, "/") + } + + return pathInfo{ + fsPath: fsPath, + urlPath: urlPath, + } } // NewLuaRouter creates a new LuaRouter instance @@ -136,12 +170,13 @@ func (r *LuaRouter) buildRoutes() error { return err } - urlPath := "/" + fsPath := "/" if relDir != "." { - urlPath = "/" + strings.ReplaceAll(relDir, "\\", "/") + fsPath = "/" + strings.ReplaceAll(relDir, "\\", "/") } - r.middlewareFiles[urlPath] = append(r.middlewareFiles[urlPath], path) + // Use filesystem path for middleware (includes groups) + r.middlewareFiles[fsPath] = append(r.middlewareFiles[fsPath], path) } return nil @@ -169,19 +204,22 @@ func (r *LuaRouter) buildRoutes() error { return err } - urlPath := "/" + fsPath := "/" if relDir != "." { - urlPath = "/" + strings.ReplaceAll(relDir, "\\", "/") + fsPath = "/" + strings.ReplaceAll(relDir, "\\", "/") } + pathInfo := parsePathWithGroups(fsPath) + // Handle index.lua files if fileName == "index" { for _, method := range []string{"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"} { root := r.routes[method] - node := r.findOrCreateNode(root, urlPath) + node := r.findOrCreateNode(root, pathInfo.urlPath) node.indexFile = path node.modTime = info.ModTime() - r.compileWithMiddleware(node, urlPath, path) + node.fsPath = pathInfo.fsPath + r.compileWithMiddleware(node, pathInfo.fsPath, path) } return nil } @@ -193,14 +231,14 @@ func (r *LuaRouter) buildRoutes() error { return nil } - r.addRoute(root, urlPath, path, info.ModTime()) + r.addRoute(root, pathInfo, path, info.ModTime()) return nil }) } // addRoute adds a route to the routing tree -func (r *LuaRouter) addRoute(root *node, urlPath, handlerPath string, modTime time.Time) error { - segments := strings.Split(strings.Trim(urlPath, "/"), "/") +func (r *LuaRouter) addRoute(root *node, pathInfo pathInfo, handlerPath string, modTime time.Time) error { + segments := strings.Split(strings.Trim(pathInfo.urlPath, "/"), "/") current := root for _, segment := range segments { @@ -230,18 +268,19 @@ func (r *LuaRouter) addRoute(root *node, urlPath, handlerPath string, modTime ti current.handler = handlerPath current.modTime = modTime + current.fsPath = pathInfo.fsPath - return r.compileWithMiddleware(current, urlPath, handlerPath) + return r.compileWithMiddleware(current, pathInfo.fsPath, handlerPath) } // compileWithMiddleware combines middleware and handler source, then compiles -func (r *LuaRouter) compileWithMiddleware(n *node, urlPath, scriptPath string) error { +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(urlPath, scriptPath) + sourceKey := r.getSourceCacheKey(fsPath, scriptPath) needsRecompile := false // Check handler modification time @@ -258,7 +297,7 @@ func (r *LuaRouter) compileWithMiddleware(n *node, urlPath, scriptPath string) e // Check middleware modification times if !needsRecompile { - middlewareChain := r.getMiddlewareChain(urlPath) + middlewareChain := r.getMiddlewareChain(fsPath) for _, mwPath := range middlewareChain { mwInfo, err := os.Stat(mwPath) if err != nil { @@ -282,7 +321,7 @@ func (r *LuaRouter) compileWithMiddleware(n *node, urlPath, scriptPath string) e } // Build combined source - combinedSource, err := r.buildCombinedSource(urlPath, scriptPath) + combinedSource, err := r.buildCombinedSource(fsPath, scriptPath) if err != nil { n.err = err return err @@ -309,11 +348,11 @@ func (r *LuaRouter) compileWithMiddleware(n *node, urlPath, scriptPath string) e } // buildCombinedSource builds the combined middleware + handler source -func (r *LuaRouter) buildCombinedSource(urlPath, scriptPath string) (string, error) { +func (r *LuaRouter) buildCombinedSource(fsPath, scriptPath string) (string, error) { var combinedSource strings.Builder - // Get middleware chain - middlewareChain := r.getMiddlewareChain(urlPath) + // Get middleware chain using filesystem path + middlewareChain := r.getMiddlewareChain(fsPath) // Add middleware in order for _, mwPath := range middlewareChain { @@ -368,20 +407,20 @@ func (r *LuaRouter) getFileContent(path string) ([]byte, error) { } // getSourceCacheKey generates a unique key for combined source -func (r *LuaRouter) getSourceCacheKey(urlPath, scriptPath string) string { - middlewareChain := r.getMiddlewareChain(urlPath) +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 path -func (r *LuaRouter) getMiddlewareChain(urlPath string) []string { +// 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 - pathParts := strings.Split(strings.Trim(urlPath, "/"), "/") + // Collect middleware from root to specific path using filesystem path (includes groups) + pathParts := strings.Split(strings.Trim(fsPath, "/"), "/") if pathParts[0] == "" { pathParts = []string{} } @@ -391,7 +430,7 @@ func (r *LuaRouter) getMiddlewareChain(urlPath string) []string { chain = append(chain, mw...) } - // Add middleware from each path level + // Add middleware from each path level (including groups) currentPath := "" for _, part := range pathParts { currentPath += "/" + part @@ -403,7 +442,7 @@ func (r *LuaRouter) getMiddlewareChain(urlPath string) []string { return chain } -// findOrCreateNode finds or creates a node at the given path +// findOrCreateNode finds or creates a node at the given URL path (excludes groups) func (r *LuaRouter) findOrCreateNode(root *node, urlPath string) *node { segments := strings.Split(strings.Trim(urlPath, "/"), "/") current := root @@ -467,7 +506,7 @@ func getBytecodeKey(handlerPath string) []byte { return uint64ToBytes(key) } -// Match finds a handler for the given method and path +// Match finds a handler for the given method and path (URL path, excludes groups) func (r *LuaRouter) Match(method, path string, params *Params) (*node, bool) { params.Count = 0 @@ -565,8 +604,12 @@ func (r *LuaRouter) GetRouteInfo(method, path string, params *Params) ([]byte, s scriptPath = n.indexFile } - urlPath := r.getNodeURLPath(n) - if err := r.compileWithMiddleware(n, urlPath, scriptPath); err != nil { + fsPath := n.fsPath + if fsPath == "" { + fsPath = "/" + } + + if err := r.compileWithMiddleware(n, fsPath, scriptPath); err != nil { return nil, handlerPath, n.err, true } @@ -602,8 +645,11 @@ func (r *LuaRouter) GetRouteInfo(method, path string, params *Params) ([]byte, s bytecode := r.bytecodeCache.Get(nil, bytecodeKey) if len(bytecode) == 0 { - urlPath := r.getNodeURLPath(node) - if err := r.compileWithMiddleware(node, urlPath, scriptPath); err != nil { + fsPath := node.fsPath + if fsPath == "" { + fsPath = "/" + } + if err := r.compileWithMiddleware(node, fsPath, scriptPath); err != nil { return nil, scriptPath, node.err, true } bytecode = r.bytecodeCache.Get(nil, bytecodeKey) @@ -617,12 +663,6 @@ func (r *LuaRouter) GetRouteInfo(method, path string, params *Params) ([]byte, s return bytecode, scriptPath, node.err, true } -// getNodeURLPath reconstructs URL path for a node (simplified) -func (r *LuaRouter) getNodeURLPath(node *node) string { - // This is a simplified implementation - in practice you'd traverse up the tree - return "/" -} - // nodeForHandler finds a node by its handler path func (r *LuaRouter) nodeForHandler(handlerPath string) (*node, bool) { r.mu.RLock() diff --git a/utils/metadata/metadata.go b/utils/metadata/metadata.go index d4140b5..b12fd7c 100644 --- a/utils/metadata/metadata.go +++ b/utils/metadata/metadata.go @@ -1,7 +1,7 @@ package metadata // Version holds the current Moonshark version -const Version = "0.1" +const Version = "1.0" // Build time information var (