mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-04 07:45:30 +00:00
95 lines
2.1 KiB
Go
95 lines
2.1 KiB
Go
package api
|
|
|
|
import (
|
|
"fmt"
|
|
pathpkg "path"
|
|
"strings"
|
|
)
|
|
|
|
type HandlerFunc func(*Context) *Response
|
|
|
|
type RouteSpec struct {
|
|
Method string
|
|
Pattern string
|
|
Handler HandlerFunc
|
|
parts []routePart
|
|
}
|
|
|
|
type routePart struct {
|
|
literal string
|
|
param string
|
|
}
|
|
|
|
func newRoute(method, pattern string, handler HandlerFunc) RouteSpec {
|
|
pattern = cleanPath(pattern)
|
|
return RouteSpec{
|
|
Method: strings.ToUpper(method),
|
|
Pattern: pattern,
|
|
Handler: handler,
|
|
parts: parseRouteParts(pattern),
|
|
}
|
|
}
|
|
|
|
func validateRoutes(routes []RouteSpec) error {
|
|
patterns := make(map[string]struct{}, len(routes))
|
|
for _, route := range routes {
|
|
if route.Method == "" || route.Pattern == "" || route.Handler == nil {
|
|
return fmt.Errorf("invalid API route: %+v", route)
|
|
}
|
|
key := route.Method + " " + route.Pattern
|
|
if _, exists := patterns[key]; exists {
|
|
return fmt.Errorf("duplicate API route: %s", key)
|
|
}
|
|
patterns[key] = struct{}{}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parseRouteParts(pattern string) []routePart {
|
|
pattern = strings.Trim(pattern, "/")
|
|
if pattern == "" {
|
|
return nil
|
|
}
|
|
segments := strings.Split(pattern, "/")
|
|
parts := make([]routePart, 0, len(segments))
|
|
for _, segment := range segments {
|
|
if strings.HasPrefix(segment, "{") && strings.HasSuffix(segment, "}") {
|
|
name := strings.TrimSuffix(strings.TrimPrefix(segment, "{"), "}")
|
|
parts = append(parts, routePart{param: name})
|
|
continue
|
|
}
|
|
parts = append(parts, routePart{literal: segment})
|
|
}
|
|
return parts
|
|
}
|
|
|
|
func (r RouteSpec) Match(rawPath string) (map[string]string, bool) {
|
|
path := strings.Trim(cleanPath(rawPath), "/")
|
|
if path == "" && len(r.parts) == 0 {
|
|
return map[string]string{}, true
|
|
}
|
|
segments := strings.Split(path, "/")
|
|
if len(segments) != len(r.parts) {
|
|
return nil, false
|
|
}
|
|
params := make(map[string]string)
|
|
for index, part := range r.parts {
|
|
if part.param != "" {
|
|
params[part.param] = segments[index]
|
|
continue
|
|
}
|
|
if part.literal != segments[index] {
|
|
return nil, false
|
|
}
|
|
}
|
|
return params, true
|
|
}
|
|
|
|
func cleanPath(rawPath string) string {
|
|
clean := pathpkg.Clean("/" + strings.TrimSpace(rawPath))
|
|
if clean == "." {
|
|
return "/"
|
|
}
|
|
return clean
|
|
}
|