diff --git a/app/cmd/route/route.go b/app/cmd/route/route.go index bf29651..b9759d3 100644 --- a/app/cmd/route/route.go +++ b/app/cmd/route/route.go @@ -17,6 +17,13 @@ import ( "net/http" ) +var hooker []func(r *gin.Engine) + +// Hook 方便插件在init时使用 +func Hook(fn ...func(r *gin.Engine)) { + hooker = append(hooker, fn...) +} + func SetupRouter() *gin.Engine { // Disable Console Color // gin.DisableConsoleColor() @@ -83,6 +90,10 @@ func SetupRouter() *gin.Engine { if c.Pprof != "" { pprof.Register(r, c.Pprof) } + for _, fn := range hooker { + fn(r) + } + reload.Push(func() { c := config.GetConfig() siteFlow(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime) diff --git a/app/theme/wp/route/route.go b/app/theme/wp/route/route.go new file mode 100644 index 0000000..43312a8 --- /dev/null +++ b/app/theme/wp/route/route.go @@ -0,0 +1,131 @@ +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 //const|reg + ConfigHandle func(*wp.Handle) +} + +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", +// ConfigHandle: $theme.Hook or nil, +// } +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, v.ConfigHandle) + 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, rr.ConfigHandle) + return + } + } +} diff --git a/app/theme/wp/wp.go b/app/theme/wp/wp.go index b4e2ae2..d0089dc 100644 --- a/app/theme/wp/wp.go +++ b/app/theme/wp/wp.go @@ -234,6 +234,7 @@ func (h *Handle) CommonComponents() { func PreRenderTemplate(h *Handle) { h.C.HTML(h.Code, h.templ, h.ginH) + h.Abort() h.StopPipe() }