diff --git a/internal/cmd/reload/reload.go b/internal/cmd/reload/reload.go
index 9b16e2c..2fc2cb2 100644
--- a/internal/cmd/reload/reload.go
+++ b/internal/cmd/reload/reload.go
@@ -1,9 +1,8 @@
package reload
import (
- "github.com/fthvgb1/wp-go/helper/slice"
"github.com/fthvgb1/wp-go/safety"
- "strings"
+ "sync"
)
var calls []func()
@@ -12,37 +11,118 @@ var str = safety.NewMap[string, string]()
var anyMap = safety.NewMap[string, any]()
-func GetAnyValBy[T any](k string, fn func() T) T {
- v, ok := anyMap.Load(k)
- if ok {
- return v.(T)
- }
- vv := fn()
- anyMap.Store(k, vv)
- return vv
+type safetyVar[T, A any] struct {
+ Val *safety.Var[val[T]]
+ mutex sync.Mutex
}
-func GetAnyValBys[T, A any](k string, a A, fn func(A) T) T {
- v, ok := anyMap.Load(k)
- if ok {
- return v.(T)
- }
- vv := fn(a)
- anyMap.Store(k, vv)
- return vv
+type val[T any] struct {
+ v T
+ ok bool
+}
+type safetyMap[K comparable, V, A any] struct {
+ val *safety.Map[K, V]
+ mutex sync.Mutex
}
-func GetStrBy[T any](key, delimiter string, t T, fn ...func(T) string) string {
- v, ok := str.Load(key)
+var safetyMaps = safety.NewMap[string, any]()
+var safetyMapLock = sync.Mutex{}
+
+func SafetyMapByFn[K comparable, V, A any](namespace string, fn func(A) V) func(key K, args A) V {
+ m := safetyMapFn[K, V, A](namespace)
+ return func(key K, a A) V {
+ v, ok := m.val.Load(key)
+ if ok {
+ return v
+ }
+ m.mutex.Lock()
+ v, ok = m.val.Load(key)
+ if ok {
+ m.mutex.Unlock()
+ return v
+ }
+ v = fn(a)
+ m.val.Store(key, v)
+ m.mutex.Unlock()
+ return v
+ }
+}
+
+func safetyMapFn[K comparable, V, A any](namespace string) *safetyMap[K, V, A] {
+ vv, ok := safetyMaps.Load(namespace)
+ var m *safetyMap[K, V, A]
+ if ok {
+ m = vv.(*safetyMap[K, V, A])
+ } else {
+ safetyMapLock.Lock()
+ vv, ok = safetyMaps.Load(namespace)
+ if ok {
+ m = vv.(*safetyMap[K, V, A])
+ } else {
+ m = &safetyMap[K, V, A]{safety.NewMap[K, V](), sync.Mutex{}}
+ Push(func() {
+ m.val.Flush()
+ })
+ safetyMaps.Store(namespace, m)
+ }
+ safetyMapLock.Unlock()
+ }
+ return m
+}
+
+func SafetyMapBy[K comparable, V, A any](namespace string, key K, a A, fn func(A) V) V {
+ m := safetyMapFn[K, V, A](namespace)
+ v, ok := m.val.Load(key)
if ok {
return v
}
- v = strings.Join(slice.Map(fn, func(vv func(T) string) string {
- return vv(t)
- }), delimiter)
- str.Store(key, v)
+ m.mutex.Lock()
+ v, ok = m.val.Load(key)
+ if ok {
+ m.mutex.Unlock()
+ return v
+ }
+ v = fn(a)
+ m.val.Store(key, v)
+ m.mutex.Unlock()
return v
}
+func GetAnyValBys[T, A any](namespace string, a A, fn func(A) T) T {
+ var vv *safetyVar[T, A]
+ vvv, ok := safetyMaps.Load(namespace)
+ if ok {
+ vv = vvv.(*safetyVar[T, A])
+ } else {
+ safetyMapLock.Lock()
+ vvv, ok = safetyMaps.Load(namespace)
+ if ok {
+ vv = vvv.(*safetyVar[T, A])
+ } else {
+ vv = &safetyVar[T, A]{safety.NewVar(val[T]{}), sync.Mutex{}}
+ Push(func() {
+ vv.Val.Flush()
+ })
+ safetyMaps.Store(namespace, vv)
+ }
+ safetyMapLock.Unlock()
+ }
+ v := vv.Val.Load()
+ if v.ok {
+ return v.v
+ }
+ vv.mutex.Lock()
+ v = vv.Val.Load()
+ if v.ok {
+ vv.mutex.Unlock()
+ return v.v
+ }
+ v.v = fn(a)
+ v.ok = true
+ vv.Val.Store(v)
+ vv.mutex.Unlock()
+ return v.v
+}
+
func Vars[T any](defaults T) *safety.Var[T] {
ss := safety.NewVar(defaults)
calls = append(calls, func() {
@@ -68,4 +148,5 @@ func Reload() {
}
anyMap.Flush()
str.Flush()
+ safetyMaps.Flush()
}
diff --git a/internal/theme/twentyfifteen/twentyfifteen.go b/internal/theme/twentyfifteen/twentyfifteen.go
index 5fb4f7c..3d43ea8 100644
--- a/internal/theme/twentyfifteen/twentyfifteen.go
+++ b/internal/theme/twentyfifteen/twentyfifteen.go
@@ -34,23 +34,38 @@ func Init(fs embed.FS) {
logs.ErrPrintln(err, "解析colorscheme失败")
}
-var pipe = wp.HandlePipe(wp.Render, widget.MiddleWare(ready)...)
+var pipe = wp.HandlePipe(wp.ExecuteHandleFn, widget.MiddleWare(ready, data)...)
func Hook(h *wp.Handle) {
pipe(h)
}
func ready(next wp.HandleFn[*wp.Handle], h *wp.Handle) {
+ wp.InitThemeArgAndConfig(configs, h)
h.GetPassword()
+ next(h)
+}
+
+func data(next wp.HandleFn[*wp.Handle], h *wp.Handle) {
+ if h.Scene() == constraints.Detail {
+ wp.Details(h)
+ } else {
+ wp.Indexs(h)
+ }
+ h.DetermineHandleFns()
+ next(h)
+}
+
+func configs(h *wp.Handle) *wp.Handle {
h.PushComponentFilterFn(widgets.Search, func(h *wp.Handle, s string, args ...any) string {
return strings.ReplaceAll(s, `class="search-submit"`, `class="search-submit screen-reader-text"`)
})
wphandle.RegisterPlugins(h, config.GetConfig().Plugins...)
-
h.PushCacheGroupHeadScript("CalCustomBackGround", 10, CalCustomBackGround, colorSchemeCss)
+ h.CommonComponents()
h.PushHandleFn(constraints.Ok, wp.NewHandleFn(components.WidgetArea, 20))
h.PushHandleFn(constraints.AllStats, wp.NewHandleFn(customHeader, 10))
- h.PushHandleFn(constraints.AllStats, wp.NewHandleFn(wp.Indexs, 100))
- h.PushHandleFn(constraints.Detail, wp.NewHandleFn(wp.Details, 100))
- next(h)
+ h.PushHandleFn(constraints.AllStats, wp.NewHandleFn(wp.IndexRender, 50))
+ h.PushHandleFn(constraints.Detail, wp.NewHandleFn(wp.DetailRender, 50))
+ return h
}
diff --git a/internal/theme/twentyseventeen/script.go b/internal/theme/twentyseventeen/script.go
index 29cd568..f62e538 100644
--- a/internal/theme/twentyseventeen/script.go
+++ b/internal/theme/twentyseventeen/script.go
@@ -7,7 +7,7 @@ import (
)
func pushScripts(h *wp.Handle) {
- h.PushCacheGroupFooterScript("head", 30, func(h *wp.Handle) string {
+ h.PushCacheGroupHeadScript("head", 30, func(h *wp.Handle) string {
head := headScript
if "dark" == wpconfig.GetThemeModsVal(ThemeName, "colorscheme", "light") {
head = fmt.Sprintf("%s\n%s", headScript, ` `)
diff --git a/internal/theme/twentyseventeen/twentyseventeen.go b/internal/theme/twentyseventeen/twentyseventeen.go
index 1231bbf..842e182 100644
--- a/internal/theme/twentyseventeen/twentyseventeen.go
+++ b/internal/theme/twentyseventeen/twentyseventeen.go
@@ -43,29 +43,35 @@ var paginate = func() plugins.PageEle {
return p
}()
-var pipe = wp.HandlePipe(wp.Render, widget.MiddleWare(ready)...)
+var pipe = wp.HandlePipe(wp.ExecuteHandleFn, widget.MiddleWare(ready, data)...)
func Hook(h *wp.Handle) {
pipe(h)
}
-func ready(next wp.HandleFn[*wp.Handle], h *wp.Handle) {
- h.GetPassword()
+func configs(h *wp.Handle) *wp.Handle {
wphandle.RegisterPlugins(h, config.GetConfig().Plugins...)
h.PushHandleFn(constraints.AllStats, wp.NewHandleFn(calClass, 20))
- h.PushHandleFn(constraints.AllStats, wp.NewHandleFn(index, 100))
- h.PushHandleFn(constraints.Detail, wp.NewHandleFn(detail, 100))
- h.PushGroupHandleFn(constraints.AllStats, 90, wp.PreCodeAndStats, wp.PreTemplate, errorsHandle)
h.PushCacheGroupHeadScript("colorScheme-customHeader", 10, colorScheme, customHeader)
- h.PushHandleFn(constraints.Ok, wp.NewHandleFn(components.WidgetArea, 20))
+ components.WidgetArea(h)
pushScripts(h)
- h.SetData("HeaderImage", getHeaderImage(h))
+ h.PushHandleFn(constraints.AllStats, wp.NewHandleFn(func(h *wp.Handle) {
+ h.SetData("HeaderImage", getHeaderImage(h))
+ }, 10))
h.SetComponentsArgs(widgets.Widget, map[string]string{
"{$before_widget}": ``,
})
+ h.PushGroupHandleFn(constraints.AllStats, 90, wp.PreTemplate, errorsHandle)
+ h.CommonComponents()
wp.SetComponentsArgsForMap(h, widgets.Search, "{$form}", searchForm)
-
+ h.PushHandleFn(constraints.AllStats, wp.NewHandleFn(wp.IndexRender, 10))
+ h.PushHandleFn(constraints.Detail, wp.NewHandleFn(wp.DetailRender, 10))
+ return h
+}
+func ready(next wp.HandleFn[*wp.Handle], h *wp.Handle) {
+ wp.InitThemeArgAndConfig(configs, h)
+ h.GetPassword()
next(h)
}
@@ -94,6 +100,17 @@ func errorsHandle(h *wp.Handle) {
}
}
+func data(next wp.HandleFn[*wp.Handle], h *wp.Handle) {
+ if h.Scene() == constraints.Detail {
+ detail(h)
+ } else {
+ index(h)
+ }
+ wp.PreCodeAndStats(h)
+ h.DetermineHandleFns()
+ next(h)
+}
+
func index(h *wp.Handle) {
if h.Scene() == constraints.Detail {
return
diff --git a/internal/theme/wp/components/widget/recentcomments.go b/internal/theme/wp/components/widget/recentcomments.go
index 67cb0ef..ba7daba 100644
--- a/internal/theme/wp/components/widget/recentcomments.go
+++ b/internal/theme/wp/components/widget/recentcomments.go
@@ -68,7 +68,7 @@ func RecentComments(h *wp.Handle, id string) string {
发表在《
%s
》
- `, t.CommentAuthor, t.CommentId, t.CommentPostId, t.PostTitle)
+ `, t.CommentAuthor, t.CommentPostId, t.CommentId, t.PostTitle)
})
s := strings.ReplaceAll(recentCommentsTemplate, "{$li}", strings.Join(comments, "\n"))
return h.ComponentFilterFnHook(widgets.RecentComments, str.Replace(s, args))
diff --git a/internal/theme/wp/customheader.go b/internal/theme/wp/customheader.go
index 1c5ef01..c049f33 100644
--- a/internal/theme/wp/customheader.go
+++ b/internal/theme/wp/customheader.go
@@ -18,7 +18,7 @@ func (h *Handle) DisplayHeaderText() bool {
func (h *Handle) GetCustomHeader() (r models.PostThumbnail, isRand bool) {
var err error
- hss := reload.GetAnyValBys("headerImages", h.theme, func(theme string) []models.PostThumbnail {
+ img := reload.GetAnyValBys("headerImages", h.theme, func(theme string) []models.PostThumbnail {
hs, er := h.GetHeaderImages(h.theme)
if er != nil {
err = er
@@ -30,7 +30,7 @@ func (h *Handle) GetCustomHeader() (r models.PostThumbnail, isRand bool) {
logs.ErrPrintln(err, "获取页眉背景图失败")
return
}
- hs := slice.Copy(hss)
+ hs := slice.Copy(img)
if len(hs) < 1 {
return
diff --git a/internal/theme/wp/customlogo.go b/internal/theme/wp/customlogo.go
index 573bcd9..1708910 100644
--- a/internal/theme/wp/customlogo.go
+++ b/internal/theme/wp/customlogo.go
@@ -6,11 +6,8 @@ import (
str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/internal/pkg/cache"
"github.com/fthvgb1/wp-go/internal/wpconfig"
- "sync"
)
-var logoLock = sync.Mutex{}
-
func CalCustomLogo(h *Handle) (r string) {
id := uint64(h.themeMods.CustomLogo)
if id < 1 {
@@ -33,9 +30,7 @@ func CalCustomLogo(h *Handle) (r string) {
"decoding": "async",
//"loading":"lazy",
}
- logoLock.Lock()
img := wpconfig.Thumbnail(logo.AttachmentMetadata, siz, "", "")
- logoLock.Unlock()
imgx["srcset"] = img.Srcset
imgx["sizes"] = img.Sizes
imgx["src"] = img.Path
diff --git a/internal/theme/wp/detail.go b/internal/theme/wp/detail.go
index 653ec86..2df6ec3 100644
--- a/internal/theme/wp/detail.go
+++ b/internal/theme/wp/detail.go
@@ -101,19 +101,33 @@ func (d *DetailHandle) ContextPost() {
}
func (d *DetailHandle) Render() {
+ d.PushHandleFn(constraints.Ok, NewHandleFn(func(h *Handle) {
+ d.PasswordProject()
+ d.RenderComment()
+ d.ginH["post"] = d.Post
+ reply := ""
+ if d.Post.CommentStatus == "open" && wpconfig.GetOption("thread_comments") == "1" {
+ reply = ``
+ }
+ d.PushGroupFooterScript(10, reply)
+ }, 10))
+
+ d.Handle.Render()
+}
+
+func DetailRender(h *Handle) {
+ if h.Stats != constraints.Ok {
+ return
+ }
+ d := h.Detail
+ d.PasswordProject()
+ d.RenderComment()
+ d.ginH["post"] = d.Post
reply := ""
if d.Post.CommentStatus == "open" && wpconfig.GetOption("thread_comments") == "1" {
reply = ``
}
d.PushGroupFooterScript(10, reply)
-
- d.PushHandleFn(constraints.Ok, NewHandleFn(func(h *Handle) {
- d.PasswordProject()
- d.RenderComment()
- d.ginH["post"] = d.Post
- }, 10))
-
- d.Handle.Render()
}
func Details(h *Handle) {
diff --git a/internal/theme/wp/index.go b/internal/theme/wp/index.go
index 3a4133c..d7fabf1 100644
--- a/internal/theme/wp/index.go
+++ b/internal/theme/wp/index.go
@@ -156,6 +156,16 @@ func (i *IndexHandle) Render() {
i.Handle.Render()
}
+func IndexRender(h *Handle) {
+ if h.scene == constraints.Detail || h.Stats != constraints.Ok {
+ return
+ }
+ i := h.Index
+ i.ExecPostsPlugin()
+ i.Pagination()
+ i.ginH["posts"] = i.Posts
+}
+
func Indexs(h *Handle) {
if h.Scene() == constraints.Detail {
return
@@ -171,7 +181,9 @@ func (i *IndexHandle) MarkSticky(posts *[]models.Posts) {
if len(a) < 1 {
return
}
+ m := i.StickMapPosts()
*posts = append(a, slice.Filter(*posts, func(post models.Posts, _ int) bool {
- return !i.IsStick(post.Id)
+ _, ok := m[post.Id]
+ return !ok
})...)
}
diff --git a/internal/theme/wp/stickyposts.go b/internal/theme/wp/stickyposts.go
index e0476a5..d88c8a8 100644
--- a/internal/theme/wp/stickyposts.go
+++ b/internal/theme/wp/stickyposts.go
@@ -14,7 +14,7 @@ import (
)
func (h *Handle) StickPosts() []models.Posts {
- return reload.GetAnyValBys("stickPosts", h, func(h *Handle) (r []models.Posts) {
+ return reload.GetAnyValBys("stickPostsSlice", h, func(h *Handle) (r []models.Posts) {
v := wpconfig.GetOption("sticky_posts")
if v == "" {
return
diff --git a/internal/theme/wp/wp.go b/internal/theme/wp/wp.go
index b1e3a4c..f1e7dde 100644
--- a/internal/theme/wp/wp.go
+++ b/internal/theme/wp/wp.go
@@ -1,6 +1,7 @@
package wp
import (
+ "fmt"
"github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/helper/slice"
str "github.com/fthvgb1/wp-go/helper/strings"
@@ -12,7 +13,6 @@ import (
"github.com/gin-gonic/gin"
"net/http"
"strings"
- "sync"
)
type Handle struct {
@@ -35,10 +35,16 @@ type Handle struct {
abort bool
componentsArgs map[string]any
componentFilterFn map[string][]func(*Handle, string, ...any) string
+ handleCall []HandleCall
}
-var configHandle = reload.Vars(&Handle{})
-var configHandleMux = sync.Mutex{}
+func (h *Handle) HandleCall() []HandleCall {
+ return h.handleCall
+}
+
+func (h *Handle) SetHandleCall(handleCall []HandleCall) {
+ h.handleCall = handleCall
+}
type HandlePlugins map[string]HandleFn[*Handle]
@@ -60,17 +66,21 @@ type HandleCall struct {
}
func InitThemeArgAndConfig(fn func(*Handle) *Handle, h *Handle) {
- hh := configHandle.Load()
- if len(hh.handleFns) < 1 {
- configHandleMux.Lock()
- hh = configHandle.Load()
- if len(hh.handleFns) < 1 {
- hh = fn(h)
- configHandle.Store(hh)
- }
- configHandleMux.Unlock()
+ hh := reload.GetAnyValBys("themeArgAndConfig", h, func(h *Handle) Handle {
+ h.components = make(map[string][]Components[string])
+ h.handleFns = make(map[int][]HandleCall)
+ h.componentsArgs = make(map[string]any)
+ h.componentFilterFn = make(map[string][]func(*Handle, string, ...any) string)
+ hh := fn(h)
+ return *hh
+ })
+ m := make(map[string][]Components[string])
+ for k, v := range hh.components {
+ vv := make([]Components[string], len(v))
+ copy(vv, v)
+ m[k] = vv // slice.Copy(v)
}
- h.components = hh.components
+ h.components = m // maps.Copy(hh.components)
h.handleFns = hh.handleFns
h.componentsArgs = hh.componentsArgs
h.componentFilterFn = hh.componentFilterFn
@@ -193,17 +203,13 @@ func NewHandle(c *gin.Context, scene int, theme string) *Handle {
mods, err := wpconfig.GetThemeMods(theme)
logs.ErrPrintln(err, "获取mods失败")
return &Handle{
- C: c,
- theme: theme,
- Session: sessions.Default(c),
- ginH: gin.H{},
- scene: scene,
- Stats: constraints.Ok,
- themeMods: mods,
- components: make(map[string][]Components[string]),
- handleFns: make(map[int][]HandleCall),
- componentsArgs: make(map[string]any),
- componentFilterFn: make(map[string][]func(*Handle, string, ...any) string),
+ C: c,
+ theme: theme,
+ Session: sessions.Default(c),
+ ginH: gin.H{},
+ scene: scene,
+ Stats: constraints.Ok,
+ themeMods: mods,
}
}
@@ -249,8 +255,11 @@ func (h *Handle) PushCacheGroupFooterScript(key string, order int, fns ...func(*
h.PushGroupCacheComponentFn(constraints.FooterScript, key, order, fns...)
}
func (h *Handle) PushGroupCacheComponentFn(name, key string, order int, fns ...func(*Handle) string) {
- v := reload.GetStrBy(key, "\n", h, fns...)
- h.PushGroupComponentStrs(name, order, v)
+ h.PushComponents(name, h.NewCacheComponent(key, order, func(h *Handle) string {
+ return strings.Join(slice.Map(fns, func(t func(*Handle) string) string {
+ return t(h)
+ }), "\n")
+ }))
}
func (h *Handle) GetPassword() {
@@ -360,7 +369,7 @@ func CalComponents(h *Handle) {
if component.Fn != nil {
v := ""
if component.CacheKey != "" {
- v = reload.GetAnyValBys(component.CacheKey, h, component.Fn)
+ v = reload.SafetyMapBy("calComponent", component.CacheKey, h, component.Fn)
} else {
v = component.Fn(h)
}
@@ -386,6 +395,42 @@ func HandlePipe[T any](initial func(T), fns ...HandlePipeFn[T]) HandleFn[T] {
}, initial)
}
+func DetermineHandleFn(h *Handle) []HandleCall {
+ calls, ok := h.handleFns[h.Stats]
+ var fns []HandleCall
+ if ok {
+ fns = append(fns, calls...)
+ }
+ calls, ok = h.handleFns[h.scene]
+ if ok {
+ fns = append(fns, calls...)
+ }
+ calls, ok = h.handleFns[constraints.AllStats]
+ if ok {
+ fns = append(fns, calls...)
+ }
+ slice.Sort(fns, func(i, j HandleCall) bool {
+ return i.Order > j.Order
+ })
+ return fns
+}
+
+func (h *Handle) DetermineHandleFns() {
+ key := fmt.Sprintf("%d-%d", h.scene, h.Stats)
+ h.handleCall = reload.SafetyMapBy("handleCalls", key, h, func(h *Handle) []HandleCall {
+ return DetermineHandleFn(h)
+ })
+}
+
+func ExecuteHandleFn(h *Handle) {
+ for _, fn := range h.handleCall {
+ fn.Fn(h)
+ if h.abort {
+ break
+ }
+ }
+}
+
func Render(h *Handle) {
switch h.scene {
case constraints.Detail: