change version, add logical route groups
This commit is contained in:
parent
39d14d0025
commit
163e94d576
@ -51,7 +51,7 @@ type LuaRouter struct {
|
|||||||
bytecodeCache *fastcache.Cache // Cache for compiled bytecode
|
bytecodeCache *fastcache.Cache // Cache for compiled bytecode
|
||||||
|
|
||||||
// Middleware tracking for path hierarchy
|
// 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
|
// New caching fields
|
||||||
middlewareCache map[string][]byte // path -> content
|
middlewareCache map[string][]byte // path -> content
|
||||||
@ -72,6 +72,40 @@ type node struct {
|
|||||||
paramChild *node // Parameter/wildcard child
|
paramChild *node // Parameter/wildcard child
|
||||||
err error // Compilation error if any
|
err error // Compilation error if any
|
||||||
modTime time.Time // Last modification time
|
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
|
// NewLuaRouter creates a new LuaRouter instance
|
||||||
@ -136,12 +170,13 @@ func (r *LuaRouter) buildRoutes() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
urlPath := "/"
|
fsPath := "/"
|
||||||
if relDir != "." {
|
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
|
return nil
|
||||||
@ -169,19 +204,22 @@ func (r *LuaRouter) buildRoutes() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
urlPath := "/"
|
fsPath := "/"
|
||||||
if relDir != "." {
|
if relDir != "." {
|
||||||
urlPath = "/" + strings.ReplaceAll(relDir, "\\", "/")
|
fsPath = "/" + strings.ReplaceAll(relDir, "\\", "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pathInfo := parsePathWithGroups(fsPath)
|
||||||
|
|
||||||
// Handle index.lua files
|
// Handle index.lua files
|
||||||
if fileName == "index" {
|
if fileName == "index" {
|
||||||
for _, method := range []string{"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"} {
|
for _, method := range []string{"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"} {
|
||||||
root := r.routes[method]
|
root := r.routes[method]
|
||||||
node := r.findOrCreateNode(root, urlPath)
|
node := r.findOrCreateNode(root, pathInfo.urlPath)
|
||||||
node.indexFile = path
|
node.indexFile = path
|
||||||
node.modTime = info.ModTime()
|
node.modTime = info.ModTime()
|
||||||
r.compileWithMiddleware(node, urlPath, path)
|
node.fsPath = pathInfo.fsPath
|
||||||
|
r.compileWithMiddleware(node, pathInfo.fsPath, path)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -193,14 +231,14 @@ func (r *LuaRouter) buildRoutes() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
r.addRoute(root, urlPath, path, info.ModTime())
|
r.addRoute(root, pathInfo, path, info.ModTime())
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// addRoute adds a route to the routing tree
|
// addRoute adds a route to the routing tree
|
||||||
func (r *LuaRouter) addRoute(root *node, urlPath, handlerPath string, modTime time.Time) error {
|
func (r *LuaRouter) addRoute(root *node, pathInfo pathInfo, handlerPath string, modTime time.Time) error {
|
||||||
segments := strings.Split(strings.Trim(urlPath, "/"), "/")
|
segments := strings.Split(strings.Trim(pathInfo.urlPath, "/"), "/")
|
||||||
current := root
|
current := root
|
||||||
|
|
||||||
for _, segment := range segments {
|
for _, segment := range segments {
|
||||||
@ -230,18 +268,19 @@ func (r *LuaRouter) addRoute(root *node, urlPath, handlerPath string, modTime ti
|
|||||||
|
|
||||||
current.handler = handlerPath
|
current.handler = handlerPath
|
||||||
current.modTime = modTime
|
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
|
// 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 == "" {
|
if scriptPath == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we need to recompile by comparing modification times
|
// Check if we need to recompile by comparing modification times
|
||||||
sourceKey := r.getSourceCacheKey(urlPath, scriptPath)
|
sourceKey := r.getSourceCacheKey(fsPath, scriptPath)
|
||||||
needsRecompile := false
|
needsRecompile := false
|
||||||
|
|
||||||
// Check handler modification time
|
// Check handler modification time
|
||||||
@ -258,7 +297,7 @@ func (r *LuaRouter) compileWithMiddleware(n *node, urlPath, scriptPath string) e
|
|||||||
|
|
||||||
// Check middleware modification times
|
// Check middleware modification times
|
||||||
if !needsRecompile {
|
if !needsRecompile {
|
||||||
middlewareChain := r.getMiddlewareChain(urlPath)
|
middlewareChain := r.getMiddlewareChain(fsPath)
|
||||||
for _, mwPath := range middlewareChain {
|
for _, mwPath := range middlewareChain {
|
||||||
mwInfo, err := os.Stat(mwPath)
|
mwInfo, err := os.Stat(mwPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -282,7 +321,7 @@ func (r *LuaRouter) compileWithMiddleware(n *node, urlPath, scriptPath string) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build combined source
|
// Build combined source
|
||||||
combinedSource, err := r.buildCombinedSource(urlPath, scriptPath)
|
combinedSource, err := r.buildCombinedSource(fsPath, scriptPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.err = err
|
n.err = err
|
||||||
return err
|
return err
|
||||||
@ -309,11 +348,11 @@ func (r *LuaRouter) compileWithMiddleware(n *node, urlPath, scriptPath string) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// buildCombinedSource builds the combined middleware + handler source
|
// 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
|
var combinedSource strings.Builder
|
||||||
|
|
||||||
// Get middleware chain
|
// Get middleware chain using filesystem path
|
||||||
middlewareChain := r.getMiddlewareChain(urlPath)
|
middlewareChain := r.getMiddlewareChain(fsPath)
|
||||||
|
|
||||||
// Add middleware in order
|
// Add middleware in order
|
||||||
for _, mwPath := range middlewareChain {
|
for _, mwPath := range middlewareChain {
|
||||||
@ -368,20 +407,20 @@ func (r *LuaRouter) getFileContent(path string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getSourceCacheKey generates a unique key for combined source
|
// getSourceCacheKey generates a unique key for combined source
|
||||||
func (r *LuaRouter) getSourceCacheKey(urlPath, scriptPath string) string {
|
func (r *LuaRouter) getSourceCacheKey(fsPath, scriptPath string) string {
|
||||||
middlewareChain := r.getMiddlewareChain(urlPath)
|
middlewareChain := r.getMiddlewareChain(fsPath)
|
||||||
var keyParts []string
|
var keyParts []string
|
||||||
keyParts = append(keyParts, middlewareChain...)
|
keyParts = append(keyParts, middlewareChain...)
|
||||||
keyParts = append(keyParts, scriptPath)
|
keyParts = append(keyParts, scriptPath)
|
||||||
return strings.Join(keyParts, "|")
|
return strings.Join(keyParts, "|")
|
||||||
}
|
}
|
||||||
|
|
||||||
// getMiddlewareChain returns middleware files that apply to the given path
|
// getMiddlewareChain returns middleware files that apply to the given filesystem path
|
||||||
func (r *LuaRouter) getMiddlewareChain(urlPath string) []string {
|
func (r *LuaRouter) getMiddlewareChain(fsPath string) []string {
|
||||||
var chain []string
|
var chain []string
|
||||||
|
|
||||||
// Collect middleware from root to specific path
|
// Collect middleware from root to specific path using filesystem path (includes groups)
|
||||||
pathParts := strings.Split(strings.Trim(urlPath, "/"), "/")
|
pathParts := strings.Split(strings.Trim(fsPath, "/"), "/")
|
||||||
if pathParts[0] == "" {
|
if pathParts[0] == "" {
|
||||||
pathParts = []string{}
|
pathParts = []string{}
|
||||||
}
|
}
|
||||||
@ -391,7 +430,7 @@ func (r *LuaRouter) getMiddlewareChain(urlPath string) []string {
|
|||||||
chain = append(chain, mw...)
|
chain = append(chain, mw...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add middleware from each path level
|
// Add middleware from each path level (including groups)
|
||||||
currentPath := ""
|
currentPath := ""
|
||||||
for _, part := range pathParts {
|
for _, part := range pathParts {
|
||||||
currentPath += "/" + part
|
currentPath += "/" + part
|
||||||
@ -403,7 +442,7 @@ func (r *LuaRouter) getMiddlewareChain(urlPath string) []string {
|
|||||||
return chain
|
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 {
|
func (r *LuaRouter) findOrCreateNode(root *node, urlPath string) *node {
|
||||||
segments := strings.Split(strings.Trim(urlPath, "/"), "/")
|
segments := strings.Split(strings.Trim(urlPath, "/"), "/")
|
||||||
current := root
|
current := root
|
||||||
@ -467,7 +506,7 @@ func getBytecodeKey(handlerPath string) []byte {
|
|||||||
return uint64ToBytes(key)
|
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) {
|
func (r *LuaRouter) Match(method, path string, params *Params) (*node, bool) {
|
||||||
params.Count = 0
|
params.Count = 0
|
||||||
|
|
||||||
@ -565,8 +604,12 @@ func (r *LuaRouter) GetRouteInfo(method, path string, params *Params) ([]byte, s
|
|||||||
scriptPath = n.indexFile
|
scriptPath = n.indexFile
|
||||||
}
|
}
|
||||||
|
|
||||||
urlPath := r.getNodeURLPath(n)
|
fsPath := n.fsPath
|
||||||
if err := r.compileWithMiddleware(n, urlPath, scriptPath); err != nil {
|
if fsPath == "" {
|
||||||
|
fsPath = "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.compileWithMiddleware(n, fsPath, scriptPath); err != nil {
|
||||||
return nil, handlerPath, n.err, true
|
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)
|
bytecode := r.bytecodeCache.Get(nil, bytecodeKey)
|
||||||
|
|
||||||
if len(bytecode) == 0 {
|
if len(bytecode) == 0 {
|
||||||
urlPath := r.getNodeURLPath(node)
|
fsPath := node.fsPath
|
||||||
if err := r.compileWithMiddleware(node, urlPath, scriptPath); err != nil {
|
if fsPath == "" {
|
||||||
|
fsPath = "/"
|
||||||
|
}
|
||||||
|
if err := r.compileWithMiddleware(node, fsPath, scriptPath); err != nil {
|
||||||
return nil, scriptPath, node.err, true
|
return nil, scriptPath, node.err, true
|
||||||
}
|
}
|
||||||
bytecode = r.bytecodeCache.Get(nil, bytecodeKey)
|
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
|
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
|
// nodeForHandler finds a node by its handler path
|
||||||
func (r *LuaRouter) nodeForHandler(handlerPath string) (*node, bool) {
|
func (r *LuaRouter) nodeForHandler(handlerPath string) (*node, bool) {
|
||||||
r.mu.RLock()
|
r.mu.RLock()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package metadata
|
package metadata
|
||||||
|
|
||||||
// Version holds the current Moonshark version
|
// Version holds the current Moonshark version
|
||||||
const Version = "0.1"
|
const Version = "1.0"
|
||||||
|
|
||||||
// Build time information
|
// Build time information
|
||||||
var (
|
var (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user