package route import ( "github.com/fthvgb1/wp-go/app/cmd/reload" "github.com/fthvgb1/wp-go/app/theme/wp" "github.com/fthvgb1/wp-go/helper/slice" "github.com/fthvgb1/wp-go/safety" "regexp" ) type Route struct { Path string Scene string Method []string Type string } var routeHook []func(Route) (Route, bool) var regRoutes *safety.Map[string, *regexp.Regexp] var routes = func() *safety.Map[string, Route] { r := safety.NewMap[string, Route]() reload.Push(func() { r.Flush() regRoutes.Flush() }) regRoutes = safety.NewMap[string, *regexp.Regexp]() return r }() // PushRoute path can be const or regex string // // eg: `(?P\w+)/(?P\w+)`, route.Route{ // Path: `(?P\w+)/(?P\w+)`, // Scene: constraints.Home, // Method: []string{"GET"}, // Type: "reg", // } func PushRoute(path string, route Route) error { if route.Type == "const" { routes.Store(path, route) return nil } re, err := regexp.Compile(route.Path) if err != nil { return err } regRoutes.Store(path, re) routes.Store(path, route) return err } func Delete(path string) { routeHook = append(routeHook, func(route Route) (Route, bool) { return route, route.Path != path }) } func Replace(path string, route Route) { routeHook = append(routeHook, func(r Route) (Route, bool) { return route, path == route.Path }) } func Hook(path string, fn func(Route) Route) { routeHook = append(routeHook, func(r Route) (Route, bool) { if path == r.Path { r = fn(r) } return r, path == r.Path }) } func ResolveRoute(h *wp.Handle) { requestURI := h.C.Request.RequestURI rs, rrs := reload.GetAnyValBys("route", struct{}{}, func(_ struct{}) func() (map[string]Route, map[string]*regexp.Regexp) { m := map[string]Route{} rrs := map[string]*regexp.Regexp{} routes.Range(func(key string, value Route) bool { vv, _ := regRoutes.Load(key) if len(routeHook) > 0 { for _, fn := range routeHook { v, ok := fn(value) if ok { m[v.Path] = v if v.Type == "reg" { if v.Path != key { vvv, err := regexp.Compile(v.Path) if err != nil { panic(err) } vv = vvv } rrs[v.Path] = vv } } } } else { m[key] = value rrs[key] = vv } return true }) return func() (map[string]Route, map[string]*regexp.Regexp) { return m, rrs } })() v, ok := rs[requestURI] if ok && slice.IsContained(v.Method, h.C.Request.Method) { h.SetScene(v.Scene) wp.Run(h, nil) return } for path, reg := range rrs { r := reg.FindAllStringSubmatch(requestURI, -1) if len(r) < 1 { return } rr := rs[path] if slice.IsContained(rr.Method, h.C.Request.Method) { h.SetScene(rr.Scene) h.C.Set("route", r) wp.Run(h, nil) return } } }