optimize code and add hook gin action and set noroute

This commit is contained in:
xing 2024-04-18 01:39:36 +08:00
parent 5eaf798a6c
commit 166bb08ed0
7 changed files with 195 additions and 127 deletions

View File

@ -8,6 +8,8 @@ import (
"github.com/fthvgb1/wp-go/app/theme" "github.com/fthvgb1/wp-go/app/theme"
"github.com/fthvgb1/wp-go/app/wpconfig" "github.com/fthvgb1/wp-go/app/wpconfig"
"github.com/fthvgb1/wp-go/cache/reload" "github.com/fthvgb1/wp-go/cache/reload"
"github.com/fthvgb1/wp-go/helper/slice"
"github.com/fthvgb1/wp-go/helper/slice/mockmap"
str "github.com/fthvgb1/wp-go/helper/strings" str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/gin-contrib/gzip" "github.com/gin-contrib/gzip"
"github.com/gin-contrib/pprof" "github.com/gin-contrib/pprof"
@ -16,11 +18,27 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
var hooker []func(r *gin.Engine) type GinHook func(*gin.Engine)
// Hook 方便插件在init时使用 var hookers mockmap.Map[string, GinHook]
func Hook(fn ...func(r *gin.Engine)) {
hooker = append(hooker, fn...) // SetGinAction 方便插件在init时使用
func SetGinAction(name string, hook GinHook, orders ...float64) {
hookers.Set(name, hook, orders...)
}
func HookGinAction(name string, fn func(item mockmap.Item[string, GinHook]) mockmap.Item[string, GinHook]) {
item := hookers.Get(name)
if item.Name == "" {
return
}
t := fn(item)
SetGinAction(name, t.Value, t.Order)
}
// DelGinAction 方便插件在init时使用
func DelGinAction(name string) {
hookers.Del(name)
} }
func SetupRouter() *gin.Engine { func SetupRouter() *gin.Engine {
@ -28,72 +46,99 @@ func SetupRouter() *gin.Engine {
// gin.DisableConsoleColor() // gin.DisableConsoleColor()
r := gin.New() r := gin.New()
c := config.GetConfig() c := config.GetConfig()
if len(c.TrustIps) > 0 { SetGinAction("initTrustIp", func(r *gin.Engine) {
err := r.SetTrustedProxies(c.TrustIps) if len(c.TrustIps) > 0 {
if err != nil { err := r.SetTrustedProxies(c.TrustIps)
panic(err) if err != nil {
panic(err)
}
} }
} }, 99.5)
SetGinAction("setTemplate", func(r *gin.Engine) {
r.HTMLRender = theme.BuildTemplate()
wpconfig.SetTemplateFs(theme.TemplateFs)
}, 90.5)
r.HTMLRender = theme.BuildTemplate()
wpconfig.SetTemplateFs(theme.TemplateFs)
siteFlowLimitMiddleware, siteFlow := middleware.FlowLimit(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime) siteFlowLimitMiddleware, siteFlow := middleware.FlowLimit(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime)
r.Use(
gin.Logger(),
middleware.ValidateServerNames(),
middleware.RecoverAndSendMail(gin.DefaultErrorWriter),
siteFlowLimitMiddleware,
middleware.SetStaticFileCache,
)
//gzip 因为一般会用nginx做反代时自动使用gzip,所以go这边本身可以不用
if c.Gzip {
r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{
"/wp-includes/", "/wp-content/",
})))
}
if c.WpDir == "" {
panic("wordpress path can't be empty")
}
r.Static("/wp-content/uploads", str.Join(c.WpDir, "/wp-content/uploads"))
r.Static("/wp-content/themes", str.Join(c.WpDir, "/wp-content/themes"))
r.Static("/wp-content/plugins", str.Join(c.WpDir, "/wp-content/plugins"))
r.Static("/wp-includes/css", str.Join(c.WpDir, "/wp-includes/css"))
r.Static("/wp-includes/fonts", str.Join(c.WpDir, "/wp-includes/fonts"))
r.Static("/wp-includes/js", str.Join(c.WpDir, "/wp-includes/js"))
store := cookie.NewStore([]byte("secret"))
r.Use(sessions.Sessions("go-wp", store))
r.GET("/", actions.Feed, middleware.SearchLimit(c.SingleIpSearchNum),
actions.ThemeHook(constraints.Home))
r.GET("/page/:page", actions.ThemeHook(constraints.Home))
r.GET("/p/category/:category", actions.ThemeHook(constraints.Category))
r.GET("/p/category/:category/page/:page", actions.ThemeHook(constraints.Category))
r.GET("/p/tag/:tag", actions.ThemeHook(constraints.Tag))
r.GET("/p/tag/:tag/page/:page", actions.ThemeHook(constraints.Tag))
r.GET("/p/date/:year/:month", actions.ThemeHook(constraints.Archive))
r.GET("/p/date/:year/:month/page/:page", actions.ThemeHook(constraints.Archive))
r.GET("/p/author/:author", actions.ThemeHook(constraints.Author))
r.GET("/p/author/:author/page/:page", actions.ThemeHook(constraints.Author))
r.POST("/login", actions.Login)
r.GET("/p/:id", actions.ThemeHook(constraints.Detail))
r.GET("/p/:id/comment-page-:page", actions.ThemeHook(constraints.Detail))
r.GET("/p/:id/feed", actions.PostFeed)
r.GET("/feed", actions.SiteFeed)
r.GET("/comments/feed", actions.CommentsFeed)
//r.NoRoute(actions.ThemeHook(constraints.NoRoute))
commentMiddleWare, _ := middleware.FlowLimit(c.MaxRequestSleepNum, 5, c.CacheTime.SleepTime)
r.POST("/comment", commentMiddleWare, actions.PostComment)
if c.Pprof != "" {
pprof.Register(r, c.Pprof)
}
for _, fn := range hooker {
fn(r)
}
reload.Append(func() { reload.Append(func() {
c := config.GetConfig() c = config.GetConfig()
siteFlow(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime) siteFlow(c.MaxRequestSleepNum, c.MaxRequestNum, c.CacheTime.SleepTime)
}, "site-flowLimit-config") }, "site-flowLimit-config")
SetGinAction("setGlobalMiddleware", func(r *gin.Engine) {
r.Use(
gin.Logger(),
middleware.ValidateServerNames(),
middleware.RecoverAndSendMail(gin.DefaultErrorWriter),
siteFlowLimitMiddleware,
middleware.SetStaticFileCache,
)
}, 88.5)
SetGinAction("setGzip", func(r *gin.Engine) {
//gzip 因为一般会用nginx做反代时自动使用gzip,所以go这边本身可以不用
if c.Gzip {
r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{
"/wp-includes/", "/wp-content/",
})))
}
}, 87.6)
SetGinAction("setWpDir", func(r *gin.Engine) {
if c.WpDir == "" {
panic("wordpress path can't be empty")
}
r.Static("/wp-content/uploads", str.Join(c.WpDir, "/wp-content/uploads"))
r.Static("/wp-content/themes", str.Join(c.WpDir, "/wp-content/themes"))
r.Static("/wp-content/plugins", str.Join(c.WpDir, "/wp-content/plugins"))
r.Static("/wp-includes/css", str.Join(c.WpDir, "/wp-includes/css"))
r.Static("/wp-includes/fonts", str.Join(c.WpDir, "/wp-includes/fonts"))
r.Static("/wp-includes/js", str.Join(c.WpDir, "/wp-includes/js"))
}, 86.1)
SetGinAction("setSession", func(r *gin.Engine) {
store := cookie.NewStore([]byte("secret"))
r.Use(sessions.Sessions("go-wp", store))
}, 85.1)
SetGinAction("setRoute", func(r *gin.Engine) {
r.GET("/", actions.Feed, middleware.SearchLimit(c.SingleIpSearchNum),
actions.ThemeHook(constraints.Home))
r.GET("/page/:page", actions.ThemeHook(constraints.Home))
r.GET("/p/category/:category", actions.ThemeHook(constraints.Category))
r.GET("/p/category/:category/page/:page", actions.ThemeHook(constraints.Category))
r.GET("/p/tag/:tag", actions.ThemeHook(constraints.Tag))
r.GET("/p/tag/:tag/page/:page", actions.ThemeHook(constraints.Tag))
r.GET("/p/date/:year/:month", actions.ThemeHook(constraints.Archive))
r.GET("/p/date/:year/:month/page/:page", actions.ThemeHook(constraints.Archive))
r.GET("/p/author/:author", actions.ThemeHook(constraints.Author))
r.GET("/p/author/:author/page/:page", actions.ThemeHook(constraints.Author))
r.POST("/login", actions.Login)
r.GET("/p/:id", actions.ThemeHook(constraints.Detail))
r.GET("/p/:id/comment-page-:page", actions.ThemeHook(constraints.Detail))
r.GET("/p/:id/feed", actions.PostFeed)
r.GET("/feed", actions.SiteFeed)
r.GET("/comments/feed", actions.CommentsFeed)
commentMiddleWare, _ := middleware.FlowLimit(c.MaxRequestSleepNum, 5, c.CacheTime.SleepTime)
r.POST("/comment", commentMiddleWare, actions.PostComment)
r.NoRoute(actions.ThemeHook(constraints.NoRoute))
}, 84.6)
SetGinAction("setpprof", func(r *gin.Engine) {
if c.Pprof != "" {
pprof.Register(r, c.Pprof)
}
}, 80.8)
slice.SimpleSort(hookers, slice.DESC, func(t mockmap.Item[string, GinHook]) float64 {
return t.Order
})
for _, fn := range hookers {
fn.Value(r)
}
return r return r
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/fthvgb1/wp-go/app/pkg/constraints" "github.com/fthvgb1/wp-go/app/pkg/constraints"
"github.com/fthvgb1/wp-go/app/theme/wp" "github.com/fthvgb1/wp-go/app/theme/wp"
"github.com/fthvgb1/wp-go/app/theme/wp/components/widget" "github.com/fthvgb1/wp-go/app/theme/wp/components/widget"
"github.com/fthvgb1/wp-go/app/theme/wp/route"
"github.com/fthvgb1/wp-go/cache/reload" "github.com/fthvgb1/wp-go/cache/reload"
"github.com/fthvgb1/wp-go/helper/maps" "github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/helper/number" "github.com/fthvgb1/wp-go/helper/number"
@ -160,4 +161,7 @@ func CommonMiddleware(h *wp.Handle) {
h.PushHandler(constraints.PipeMiddleware, constraints.Detail, h.PushHandler(constraints.PipeMiddleware, constraints.Detail,
wp.NewHandleFn(ShowPreComment, 100, "middleware.ShowPreComment"), wp.NewHandleFn(ShowPreComment, 100, "middleware.ShowPreComment"),
) )
h.PushHandler(constraints.PipeMiddleware, constraints.NoRoute,
wp.NewHandleFn(route.ResolveRoute, 100, "route.ResolveRoute"),
)
} }

View File

@ -5,9 +5,12 @@ import (
"github.com/fthvgb1/wp-go/cache/reload" "github.com/fthvgb1/wp-go/cache/reload"
"github.com/fthvgb1/wp-go/helper/slice" "github.com/fthvgb1/wp-go/helper/slice"
"github.com/fthvgb1/wp-go/safety" "github.com/fthvgb1/wp-go/safety"
"net/http"
"regexp" "regexp"
) )
// Route
// Type value equal const or reg
type Route struct { type Route struct {
Path string Path string
Scene string Scene string
@ -131,4 +134,6 @@ func ResolveRoute(h *wp.Handle) {
return return
} }
} }
h.C.Status(http.StatusNotFound)
h.Abort()
} }

View File

@ -5,7 +5,7 @@ import (
"github.com/fthvgb1/wp-go/cache" "github.com/fthvgb1/wp-go/cache"
"github.com/fthvgb1/wp-go/cache/reload" "github.com/fthvgb1/wp-go/cache/reload"
"github.com/fthvgb1/wp-go/helper" "github.com/fthvgb1/wp-go/helper"
"github.com/fthvgb1/wp-go/helper/slice" "github.com/fthvgb1/wp-go/helper/slice/mockmap"
str "github.com/fthvgb1/wp-go/helper/strings" str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/safety" "github.com/fthvgb1/wp-go/safety"
"runtime" "runtime"
@ -15,52 +15,20 @@ import (
var mutex sync.Mutex var mutex sync.Mutex
type Queue struct { type Fn func(context.Context)
Name string
Fn func(context.Context)
}
type Queues []Queue
func (q *Queues) Get(name string) Queue {
_, v := slice.SearchFirst(*q, func(t Queue) bool {
return name == t.Name
})
return v
}
func (q *Queues) Set(name string, fn func(context.Context)) {
i := slice.IndexOfBy(*q, func(t Queue) bool {
return name == t.Name
})
if i > -1 {
(*q)[i].Fn = fn
return
}
*q = append(*q, Queue{name, fn})
}
func (q *Queues) Del(name string) {
i := slice.IndexOfBy(*q, func(t Queue) bool {
return name == t.Name
})
if i > -1 {
slice.Delete((*[]Queue)(q), i)
}
}
type clearExpired interface { type clearExpired interface {
ClearExpired(ctx context.Context) ClearExpired(ctx context.Context)
} }
var clears = safety.NewVar(Queues{}) var clears = safety.NewVar(mockmap.Map[string, Fn]{})
var flushes = safety.NewVar(Queues{}) var flushes = safety.NewVar(mockmap.Map[string, Fn]{})
func Flush() { func Flush() {
ctx := context.WithValue(context.Background(), "execFlushBy", "mangerFlushFn") ctx := context.WithValue(context.Background(), "execFlushBy", "mangerFlushFn")
for _, f := range flushes.Load() { for _, f := range flushes.Load() {
f.Fn(ctx) f.Value(ctx)
} }
} }
@ -68,12 +36,12 @@ func Flushes(ctx context.Context, names ...string) {
execute(ctx, flushes, names...) execute(ctx, flushes, names...)
} }
func execute(ctx context.Context, q *safety.Var[Queues], names ...string) { func execute(ctx context.Context, q *safety.Var[mockmap.Map[string, Fn]], names ...string) {
queues := q.Load() queues := q.Load()
for _, name := range names { for _, name := range names {
queue := queues.Get(name) queue := queues.Get(name)
if queue.Fn != nil { if queue.Value != nil {
queue.Fn(ctx) queue.Value(ctx)
} }
} }
} }
@ -118,9 +86,9 @@ func buildLockFn[K comparable](args ...any) cache.LockFn[K] {
} else { } else {
lo := cache.NewLocks[K](loFn) lo := cache.NewLocks[K](loFn)
lockFn = lo.GetLock lockFn = lo.GetLock
PushOrSetFlush(Queue{ PushOrSetFlush(mockmap.Item[string, Fn]{
Name: name, Name: name,
Fn: lo.Flush, Value: lo.Flush,
}) })
} }
@ -141,14 +109,14 @@ func ChangeExpireTime(t time.Duration, coverConf bool, name ...string) {
reload.SetFnVal(s, t, coverConf) reload.SetFnVal(s, t, coverConf)
} }
} }
func pushOrSet(q *safety.Var[Queues], queues ...Queue) { func pushOrSet(q *safety.Var[mockmap.Map[string, Fn]], queues ...mockmap.Item[string, Fn]) {
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()
qu := q.Load() qu := q.Load()
for _, queue := range queues { for _, queue := range queues {
v := qu.Get(queue.Name) v := qu.Get(queue.Name)
if v.Fn != nil { if v.Value != nil {
qu.Set(queue.Name, queue.Fn) qu.Set(queue.Name, queue.Value)
} else { } else {
qu = append(qu, queue) qu = append(qu, queue)
} }
@ -157,16 +125,16 @@ func pushOrSet(q *safety.Var[Queues], queues ...Queue) {
} }
// PushOrSetFlush will execute flush func when call Flush or Flushes // PushOrSetFlush will execute flush func when call Flush or Flushes
func PushOrSetFlush(queues ...Queue) { func PushOrSetFlush(queues ...mockmap.Item[string, Fn]) {
pushOrSet(flushes, queues...) pushOrSet(flushes, queues...)
} }
// PushOrSetClearExpired will execute clearExpired func when call ClearExpired or ClearExpireds // PushOrSetClearExpired will execute clearExpired func when call ClearExpired or ClearExpireds
func PushOrSetClearExpired(queues ...Queue) { func PushOrSetClearExpired(queues ...mockmap.Item[string, Fn]) {
pushOrSet(clears, queues...) pushOrSet(clears, queues...)
} }
func del(q *safety.Var[Queues], names ...string) { func del(q *safety.Var[mockmap.Map[string, Fn]], names ...string) {
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()
queues := q.Load() queues := q.Load()
@ -190,6 +158,6 @@ func ClearExpireds(ctx context.Context, names ...string) {
func ClearExpired() { func ClearExpired() {
ctx := context.WithValue(context.Background(), "execClearExpired", "mangerClearExpiredFn") ctx := context.WithValue(context.Background(), "execClearExpired", "mangerClearExpiredFn")
for _, queue := range clears.Load() { for _, queue := range clears.Load() {
queue.Fn(ctx) queue.Value(ctx)
} }
} }

View File

@ -5,6 +5,7 @@ import (
"errors" "errors"
"github.com/fthvgb1/wp-go/cache" "github.com/fthvgb1/wp-go/cache"
"github.com/fthvgb1/wp-go/helper" "github.com/fthvgb1/wp-go/helper"
"github.com/fthvgb1/wp-go/helper/slice/mockmap"
str "github.com/fthvgb1/wp-go/helper/strings" str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/safety" "github.com/fthvgb1/wp-go/safety"
"time" "time"
@ -110,13 +111,13 @@ func NewMapCache[K comparable, V any](data cache.Cache[K, V], batchFn cache.MapB
if name != "" { if name != "" {
PushMangerMap(name, m) PushMangerMap(name, m)
} }
PushOrSetFlush(Queue{ PushOrSetFlush(mockmap.Item[string, Fn]{
Name: name, Name: name,
Fn: m.Flush, Value: m.Flush,
}) })
PushOrSetClearExpired(Queue{ PushOrSetClearExpired(mockmap.Item[string, Fn]{
Name: name, Name: name,
Fn: m.ClearExpired, Value: m.ClearExpired,
}) })
if f != nil && name != "" { if f != nil && name != "" {
SetExpireTime(any(data).(cache.SetTime), name, 0, f) SetExpireTime(any(data).(cache.SetTime), name, 0, f)

View File

@ -5,6 +5,7 @@ import (
"errors" "errors"
"github.com/fthvgb1/wp-go/cache" "github.com/fthvgb1/wp-go/cache"
"github.com/fthvgb1/wp-go/helper" "github.com/fthvgb1/wp-go/helper"
"github.com/fthvgb1/wp-go/helper/slice/mockmap"
str "github.com/fthvgb1/wp-go/helper/strings" str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/safety" "github.com/fthvgb1/wp-go/safety"
"time" "time"
@ -35,15 +36,15 @@ func NewVarCache[T any](c cache.AnyCache[T], fn func(context.Context, ...any) (T
if name != "" { if name != "" {
varCache.Store(name, v) varCache.Store(name, v)
} }
PushOrSetFlush(Queue{ PushOrSetFlush(mockmap.Item[string, Fn]{
Name: name, Name: name,
Fn: v.Flush, Value: v.Flush,
}) })
cc, ok := any(c).(clearExpired) cc, ok := any(c).(clearExpired)
if ok { if ok {
PushOrSetClearExpired(Queue{ PushOrSetClearExpired(mockmap.Item[string, Fn]{
Name: name, Name: name,
Fn: cc.ClearExpired, Value: cc.ClearExpired,
}) })
} }
return v return v

View File

@ -0,0 +1,44 @@
package mockmap
import (
"github.com/fthvgb1/wp-go/helper/slice"
)
type Item[K comparable, T any] struct {
Name K
Value T
Order float64
}
type Map[K comparable, T any] []Item[K, T]
func (q *Map[K, T]) Get(name K) Item[K, T] {
_, v := slice.SearchFirst(*q, func(t Item[K, T]) bool {
return name == t.Name
})
return v
}
func (q *Map[K, T]) Set(name K, value T, orders ...float64) {
i := slice.IndexOfBy(*q, func(t Item[K, T]) bool {
return name == t.Name
})
if i > -1 {
(*q)[i].Value = value
return
}
order := float64(0)
if len(orders) > 0 {
order = orders[0]
}
*q = append(*q, Item[K, T]{name, value, order})
}
func (q *Map[K, T]) Del(name K) {
i := slice.IndexOfBy(*q, func(t Item[K, T]) bool {
return name == t.Name
})
if i > -1 {
slice.Delete((*[]Item[K, T])(q), i)
}
}