optimize code, fix bug and add some comments

This commit is contained in:
xing 2024-01-18 23:29:50 +08:00
parent 8bdc53d175
commit 5e18c9babd
33 changed files with 924 additions and 599 deletions

View File

@ -10,8 +10,6 @@ func ThemeHook(scene string) func(*gin.Context) {
return func(c *gin.Context) { return func(c *gin.Context) {
t := theme.GetCurrentTemplateName() t := theme.GetCurrentTemplateName()
h := wp.NewHandle(c, scene, t) h := wp.NewHandle(c, scene, t)
h.Index = wp.NewIndexHandle(h)
h.Detail = wp.NewDetailHandle(h)
templ, _ := theme.GetTemplate(t) templ, _ := theme.GetTemplate(t)
h.SetTemplate(templ) h.SetTemplate(templ)
theme.Hook(t, h) theme.Hook(t, h)

View File

@ -19,9 +19,9 @@ func FlowLimit(maxRequestSleepNum, maxRequestNum int64, sleepTime []time.Duratio
} }
s := safety.Var[[]time.Duration]{} s := safety.Var[[]time.Duration]{}
s.Store(sleepTime) s.Store(sleepTime)
fn := func(msn, mn int64, st []time.Duration) { fn := func(sleepNum, maxNum int64, st []time.Duration) {
atomic.StoreInt64(&maxRequestSleepNum, msn) atomic.StoreInt64(&maxRequestSleepNum, sleepNum)
atomic.StoreInt64(&maxRequestNum, mn) atomic.StoreInt64(&maxRequestNum, maxNum)
s.Store(st) s.Store(st)
} }
return func(c *gin.Context) { return func(c *gin.Context) {

View File

@ -25,14 +25,25 @@ func IpLimit(num int64) (func(ctx *gin.Context), func(int64)) {
fn(num) fn(num)
return func(c *gin.Context) { return func(c *gin.Context) {
if atomic.LoadInt64(m.limitNum) <= 0 {
c.Next()
return
}
ip := c.ClientIP() ip := c.ClientIP()
s := false
m.mux.RLock() m.mux.RLock()
i, ok := m.m[ip] i, ok := m.m[ip]
m.mux.RUnlock() m.mux.RUnlock()
if !ok {
m.mux.Lock()
i = new(int64)
m.m[ip] = i
m.mux.Unlock()
}
defer func() { defer func() {
ii := atomic.LoadInt64(i) ii := atomic.LoadInt64(i)
if s && ii > 0 { if ii > 0 {
atomic.AddInt64(i, -1) atomic.AddInt64(i, -1)
if atomic.LoadInt64(i) == 0 { if atomic.LoadInt64(i) == 0 {
m.mux.Lock() m.mux.Lock()
@ -42,20 +53,12 @@ func IpLimit(num int64) (func(ctx *gin.Context), func(int64)) {
} }
}() }()
if !ok { if atomic.LoadInt64(i) >= atomic.LoadInt64(m.limitNum) {
m.mux.Lock()
i = new(int64)
m.m[ip] = i
m.mux.Unlock()
}
if atomic.LoadInt64(m.limitNum) > 0 && atomic.LoadInt64(i) >= atomic.LoadInt64(m.limitNum) {
c.Status(http.StatusForbidden) c.Status(http.StatusForbidden)
c.Abort() c.Abort()
return return
} }
atomic.AddInt64(i, 1) atomic.AddInt64(i, 1)
s = true
c.Next() c.Next()
}, fn }, fn
} }

View File

@ -39,9 +39,11 @@ func InitDb() (*safety.Var[*sqlx.DB], error) {
if preDb != nil { if preDb != nil {
_ = preDb.Close() _ = preDb.Close()
} }
showQuerySql = reload.FnVal("showQuerySql", false, func() bool { if showQuerySql == nil {
return config.GetConfig().ShowQuerySql showQuerySql = reload.BuildFnVal("showQuerySql", false, func() bool {
}) return config.GetConfig().ShowQuerySql
})
}
return safeDb, err return safeDb, err
} }

View File

@ -23,7 +23,7 @@ func configs(h *wp.Handle) {
}) })
wp.InitPipe(h) wp.InitPipe(h)
middleware.CommonMiddleware(h) middleware.CommonMiddleware(h)
h.Index.SetPageEle(plugins.TwentyFifteenPagination()) setPaginationAndRender(h)
h.PushCacheGroupHeadScript(constraints.AllScene, "CalCustomBackGround", 10.005, CalCustomBackGround) h.PushCacheGroupHeadScript(constraints.AllScene, "CalCustomBackGround", 10.005, CalCustomBackGround)
h.PushCacheGroupHeadScript(constraints.AllScene, "colorSchemeCss", 10.0056, colorSchemeCss) h.PushCacheGroupHeadScript(constraints.AllScene, "colorSchemeCss", 10.0056, colorSchemeCss)
h.CommonComponents() h.CommonComponents()
@ -39,8 +39,22 @@ func configs(h *wp.Handle) {
h.PushRender(constraints.AllScene, wp.NewHandleFn(wp.PreTemplate, 70.005, "wp.PreTemplate")) h.PushRender(constraints.AllScene, wp.NewHandleFn(wp.PreTemplate, 70.005, "wp.PreTemplate"))
} }
func setPaginationAndRender(h *wp.Handle) {
h.PushHandler(constraints.PipeRender, constraints.Detail, wp.NewHandleFn(func(hh *wp.Handle) {
d := hh.GetDetailHandle()
d.CommentRender = plugins.CommentRender()
d.CommentPageEle = plugins.TwentyFifteenCommentPagination()
}, 150, "setPaginationAndRender"))
wp.PushIndexHandler(constraints.PipeRender, h, wp.NewHandleFn(func(hh *wp.Handle) {
i := hh.GetIndexHandle()
i.SetPageEle(plugins.TwentyFifteenPagination())
}, 150, "setPaginationAndRender"))
}
func postThumb(h *wp.Handle) { func postThumb(h *wp.Handle) {
if h.Detail.Post.Thumbnail.Path != "" { d := h.GetDetailHandle()
h.Detail.Post.Thumbnail = wpconfig.Thumbnail(h.Detail.Post.Thumbnail.OriginAttachmentData, "post-thumbnail", "") if d.Post.Thumbnail.Path != "" {
d.Post.Thumbnail = wpconfig.Thumbnail(d.Post.Thumbnail.OriginAttachmentData, "post-thumbnail", "")
} }
} }

View File

@ -57,7 +57,7 @@ func configs(h *wp.Handle) {
components.WidgetArea(h) components.WidgetArea(h)
pushScripts(h) pushScripts(h)
h.PushRender(constraints.AllStats, wp.NewHandleFn(calCustomHeader, 10.005, "calCustomHeader")) h.PushRender(constraints.AllStats, wp.NewHandleFn(calCustomHeader, 10.005, "calCustomHeader"))
wp.SetComponentsArgs(h, widgets.Widget, map[string]string{ wp.SetComponentsArgs(widgets.Widget, map[string]string{
"{$before_widget}": `<section id="%s" class="%s">`, "{$before_widget}": `<section id="%s" class="%s">`,
"{$after_widget}": `</section>`, "{$after_widget}": `</section>`,
}) })
@ -67,13 +67,11 @@ func configs(h *wp.Handle) {
) )
videoHeader(h) videoHeader(h)
h.SetData("colophon", colophon) h.SetData("colophon", colophon)
h.Detail.CommentRender = commentFormat setPaginationAndRender(h)
h.Detail.CommentPageEle = commentPageEle
h.CommonComponents() h.CommonComponents()
h.Index.SetPageEle(paginate)
wp.ReplyCommentJs(h) wp.ReplyCommentJs(h)
h.PushPostPlugin(postThumbnail) h.PushPostPlugin(postThumbnail)
wp.SetComponentsArgsForMap(h, widgets.Search, "{$form}", searchForm) wp.SetComponentsArgsForMap(widgets.Search, "{$form}", searchForm)
wp.PushIndexHandler(constraints.PipeRender, h, wp.NewHandleFn(wp.IndexRender, 10.005, "wp.IndexRender")) wp.PushIndexHandler(constraints.PipeRender, h, wp.NewHandleFn(wp.IndexRender, 10.005, "wp.IndexRender"))
h.PushRender(constraints.Detail, wp.NewHandleFn(wp.DetailRender, 10.005, "wp.DetailRender")) h.PushRender(constraints.Detail, wp.NewHandleFn(wp.DetailRender, 10.005, "wp.DetailRender"))
h.PushDataHandler(constraints.Detail, wp.NewHandleFn(wp.Detail, 100.005, "wp.Detail"), wp.NewHandleFn(postThumb, 90.005, "{theme}.postThumb")) h.PushDataHandler(constraints.Detail, wp.NewHandleFn(wp.Detail, 100.005, "wp.Detail"), wp.NewHandleFn(postThumb, 90.005, "{theme}.postThumb"))
@ -81,6 +79,18 @@ func configs(h *wp.Handle) {
h.PushDataHandler(constraints.AllScene, wp.NewHandleFn(wp.PreCodeAndStats, 90.005, "wp.PreCodeAndStats")) h.PushDataHandler(constraints.AllScene, wp.NewHandleFn(wp.PreCodeAndStats, 90.005, "wp.PreCodeAndStats"))
} }
func setPaginationAndRender(h *wp.Handle) {
h.PushHandler(constraints.PipeRender, constraints.Detail, wp.NewHandleFn(func(hh *wp.Handle) {
d := hh.GetDetailHandle()
d.CommentRender = commentFormat
d.CommentPageEle = commentPageEle
}, 150, "setPaginationAndRender"))
wp.PushIndexHandler(constraints.PipeRender, h, wp.NewHandleFn(func(hh *wp.Handle) {
i := hh.GetIndexHandle()
i.SetPageEle(paginate)
}, 150, "setPaginationAndRender"))
}
var searchForm = `<form role="search" method="get" class="search-form" action="/"> var searchForm = `<form role="search" method="get" class="search-form" action="/">
<label for="search-form-1"> <label for="search-form-1">
<span class="screen-reader-text">{$label}</span> <span class="screen-reader-text">{$label}</span>
@ -101,7 +111,7 @@ func errorsHandle(h *wp.Handle) {
} }
func postThumb(h *wp.Handle) { func postThumb(h *wp.Handle) {
d := h.Detail d := h.GetDetailHandle()
if d.Post.Thumbnail.Path != "" { if d.Post.Thumbnail.Path != "" {
img := wpconfig.Thumbnail(d.Post.Thumbnail.OriginAttachmentData, "full", "", "thumbnail", "post-thumbnail") img := wpconfig.Thumbnail(d.Post.Thumbnail.OriginAttachmentData, "full", "", "thumbnail", "post-thumbnail")
img.Sizes = "100vw" img.Sizes = "100vw"

View File

@ -33,14 +33,14 @@ func (h *Handle) BodyClass() string {
case constraints.Search: case constraints.Search:
s := "search-no-results" s := "search-no-results"
if len(h.Index.Posts) > 0 { if len(h.GetIndexHandle().Posts) > 0 {
s = "search-results" s = "search-results"
} }
class = append(class, "search", s) class = append(class, "search", s)
case constraints.Category, constraints.Tag: case constraints.Category, constraints.Tag:
class = append(class, "archive", "category") class = append(class, "archive", "category")
cat := h.Index.Param.Category cat := h.GetIndexHandle().Param.Category
if cat == "" { if cat == "" {
break break
} }
@ -54,7 +54,7 @@ func (h *Handle) BodyClass() string {
case constraints.Author: case constraints.Author:
class = append(class, "archive", "author") class = append(class, "archive", "author")
author := h.Index.Param.Author author := h.GetIndexHandle().Param.Author
user, _ := cache.GetUserByName(h.C, author) user, _ := cache.GetUserByName(h.C, author)
class = append(class, str.Join("author-", number.IntToString(user.Id))) class = append(class, str.Join("author-", number.IntToString(user.Id)))
if user.DisplayName[0] != '%' { if user.DisplayName[0] != '%' {
@ -63,7 +63,7 @@ func (h *Handle) BodyClass() string {
case constraints.Detail: case constraints.Detail:
class = append(class, "post-template-default", "single", "single-post") class = append(class, "post-template-default", "single", "single-post")
class = append(class, str.Join("postid-", number.IntToString(h.Detail.Post.Id))) class = append(class, str.Join("postid-", number.IntToString(h.GetDetailHandle().Post.Id)))
if len(h.themeMods.ThemeSupport.PostFormats) > 0 { if len(h.themeMods.ThemeSupport.PostFormats) > 0 {
class = append(class, "single-format-standard") class = append(class, "single-format-standard")
} }

View File

@ -6,57 +6,106 @@ import (
"github.com/fthvgb1/wp-go/helper/maps" "github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/helper/slice" "github.com/fthvgb1/wp-go/helper/slice"
str "github.com/fthvgb1/wp-go/helper/strings" str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/safety"
"strings" "strings"
) )
var handleComponents = safety.NewMap[string, map[string][]Components[string]]()
var handleComponentHook = safety.NewMap[string, []func(Components[string]) (Components[string], bool)]()
var componentsArgs = safety.NewMap[string, any]()
var componentFilterFns = safety.NewMap[string, []func(*Handle, string, ...any) string]()
func (h *Handle) DeleteComponents(scene, name string) { func (h *Handle) DeleteComponents(scene, name string) {
h.componentHook[scene] = append(h.componentHook[scene], func(c Components[string]) (Components[string], bool) { v, _ := handleComponentHook.Load(scene)
v = append(v, func(c Components[string]) (Components[string], bool) {
return c, c.Name != name return c, c.Name != name
}) })
handleComponentHook.Store(scene, v)
} }
func (h *Handle) ReplaceComponents(scene, name string, components Components[string]) { func (h *Handle) ReplaceComponents(scene, name string, components Components[string]) {
h.componentHook[scene] = append(h.componentHook[scene], func(c Components[string]) (Components[string], bool) { v, _ := handleComponentHook.Load(scene)
v = append(v, func(c Components[string]) (Components[string], bool) {
if c.Name == name { if c.Name == name {
c = components c = components
} }
return c, true return c, true
}) })
handleComponentHook.Store(scene, v)
} }
func (h *Handle) HookComponents(scene string, fn func(Components[string]) (Components[string], bool)) { func (h *Handle) HookComponents(scene string, fn func(Components[string]) (Components[string], bool)) {
h.componentHook[scene] = append(h.componentHook[scene], fn) v, _ := handleComponentHook.Load(scene)
v = append(v, fn)
handleComponentHook.Store(scene, v)
}
var getComponentFn = reload.BuildMapFn[string]("scene-components", getComponent)
var hookComponentFn = reload.BuildMapFn[string]("calComponents", hookComponent)
type componentParam struct {
components []Components[string]
k string
}
func hookComponent(p componentParam) []Components[string] {
mut := reload.GetGlobeMutex()
mut.Lock()
allHooks := slice.FilterAndToMap(p.components, func(t Components[string], _ int) (string, []func(Components[string]) (Components[string], bool), bool) {
fn, ok := handleComponentHook.Load(p.k)
return p.k, fn, ok
})
mut.Unlock()
r := slice.FilterAndMap(p.components, func(component Components[string]) (Components[string], bool) {
hooks, ok := allHooks[p.k]
if !ok {
return component, true
}
for _, fn := range hooks {
hookedComponent, ok := fn(component)
if !ok { // DeleteComponents fn
return hookedComponent, false
}
component = hookedComponent // ReplaceComponents fn
}
return component, true
})
slice.SimpleSort(r, slice.DESC, func(t Components[string]) float64 {
return t.Order
})
return r
}
func getComponent(h *Handle) map[string][]Components[string] {
mut := reload.GetGlobeMutex()
mut.Lock()
sceneComponents, _ := handleComponents.Load(h.scene)
allSceneComponents, _ := handleComponents.Load(constraints.AllScene)
mut.Unlock()
return maps.MergeBy(func(k string, c1, c2 []Components[string]) ([]Components[string], bool) {
vv := append(c1, c2...)
return vv, vv != nil
}, nil, sceneComponents, allSceneComponents)
}
type cacheComponentParm[T any] struct {
Components[T]
h *Handle
}
var cacheComponentsFn = reload.BuildMapFn[string]("cacheComponents", cacheComponentFn)
func cacheComponentFn(a cacheComponentParm[string]) string {
return a.Fn(a.h)
} }
func CalComponents(h *Handle) { func CalComponents(h *Handle) {
componentss := reload.GetAnyValMapBy("scene-components", str.Join("allScene-", h.scene), h, func(h *Handle) (map[string][]Components[string], bool) { allComponents := getComponentFn(str.Join("allScene-", h.scene), h)
return maps.MergeBy(func(k string, v1, v2 []Components[string]) ([]Components[string], bool) { for k, components := range allComponents {
vv := append(v1, v2...)
return vv, vv != nil
}, nil, h.components[h.scene], h.components[constraints.AllScene]), true
})
for k, components := range componentss {
key := str.Join("calComponents-", h.scene, "-", k) key := str.Join("calComponents-", h.scene, "-", k)
ss := reload.GetAnyValMapBy("calComponents", key, h, func(h *Handle) ([]Components[string], bool) { hookedComponents := hookComponentFn(key, componentParam{components, k})
r := slice.FilterAndMap(components, func(t Components[string]) (Components[string], bool) { var s = make([]string, 0, len(hookedComponents))
fns, ok := h.componentHook[k] for _, component := range hookedComponents {
if !ok {
return t, true
}
for _, fn := range fns {
c, ok := fn(t)
if !ok {
return c, false
}
t = c
}
return t, true
})
slice.SimpleSort(r, slice.DESC, func(t Components[string]) float64 {
return t.Order
})
return r, true
})
var s = make([]string, 0, len(ss))
for _, component := range ss {
if component.Val != "" { if component.Val != "" {
s = append(s, component.Val) s = append(s, component.Val)
continue continue
@ -64,9 +113,7 @@ func CalComponents(h *Handle) {
if component.Fn != nil { if component.Fn != nil {
v := "" v := ""
if component.Cached { if component.Cached {
v = reload.GetAnyValMapBy("cacheComponents", component.Name, h, func(a *Handle) (string, bool) { v = cacheComponentsFn(component.Name, cacheComponentParm[string]{component, h})
return component.Fn(h), true
})
} else { } else {
v = component.Fn(h) v = component.Fn(h)
} }
@ -80,12 +127,12 @@ func CalComponents(h *Handle) {
} }
func (h *Handle) PushComponents(scene, componentType string, components ...Components[string]) { func (h *Handle) PushComponents(scene, componentType string, components ...Components[string]) {
c, ok := h.components[scene] c, ok := handleComponents.Load(scene)
if !ok { if !ok {
c = make(map[string][]Components[string]) c = make(map[string][]Components[string])
h.components[scene] = c
} }
c[componentType] = append(c[componentType], components...) c[componentType] = append(c[componentType], components...)
handleComponents.Store(scene, c)
} }
func (h *Handle) PushGroupComponentStr(scene, componentType, name string, order float64, strs ...string) { func (h *Handle) PushGroupComponentStr(scene, componentType, name string, order float64, strs ...string) {
@ -141,8 +188,8 @@ func (h *Handle) PushGroupHeadScript(scene, name string, order float64, str ...s
h.PushGroupComponentStr(scene, constraints.HeadScript, name, order, str...) h.PushGroupComponentStr(scene, constraints.HeadScript, name, order, str...)
} }
func GetComponentsArgs[T any](h *Handle, k string, defaults T) T { func GetComponentsArgs[T any](k string, defaults T) T {
v, ok := h.componentsArgs[k] v, ok := componentsArgs.Load(k)
if ok { if ok {
vv, ok := v.(T) vv, ok := v.(T)
if ok { if ok {
@ -152,60 +199,61 @@ func GetComponentsArgs[T any](h *Handle, k string, defaults T) T {
return defaults return defaults
} }
func PushComponentsArgsForSlice[T any](h *Handle, name string, v ...T) { func PushComponentsArgsForSlice[T any](name string, v ...T) {
val, ok := h.componentsArgs[name] val, ok := componentsArgs.Load(name)
if !ok { if !ok {
var vv []T var vv []T
vv = append(vv, v...) vv = append(vv, v...)
h.componentsArgs[name] = vv componentsArgs.Store(name, vv)
return return
} }
vv, ok := val.([]T) vv, ok := val.([]T)
if ok { if ok {
vv = append(vv, v...) vv = append(vv, v...)
h.componentsArgs[name] = vv componentsArgs.Store(name, vv)
} }
} }
func SetComponentsArgsForMap[K comparable, V any](h *Handle, name string, key K, v V) { func SetComponentsArgsForMap[K comparable, V any](name string, key K, v V) {
val, ok := h.componentsArgs[name] val, ok := componentsArgs.Load(name)
if !ok { if !ok {
vv := make(map[K]V) vv := make(map[K]V)
vv[key] = v vv[key] = v
h.componentsArgs[name] = vv componentsArgs.Store(name, vv)
return return
} }
vv, ok := val.(map[K]V) vv, ok := val.(map[K]V)
if ok { if ok {
vv[key] = v vv[key] = v
h.componentsArgs[name] = vv componentsArgs.Store(name, vv)
} }
} }
func MergeComponentsArgsForMap[K comparable, V any](h *Handle, name string, m map[K]V) { func MergeComponentsArgsForMap[K comparable, V any](name string, m map[K]V) {
val, ok := h.componentsArgs[name] val, ok := componentsArgs.Load(name)
if !ok { if !ok {
h.componentsArgs[name] = m componentsArgs.Store(name, m)
return return
} }
vv, ok := val.(map[K]V) vv, ok := val.(map[K]V)
if ok { if ok {
h.componentsArgs[name] = maps.Merge(vv, m) componentsArgs.Store(name, maps.Merge(vv, m))
} }
} }
func SetComponentsArgs(h *Handle, key string, value any) { func SetComponentsArgs(key string, value any) {
h.componentsArgs[key] = value componentsArgs.Store(key, value)
} }
func (h *Handle) ComponentFilterFn(name string) ([]func(*Handle, string, ...any) string, bool) { func (h *Handle) GetComponentFilterFn(name string) ([]func(*Handle, string, ...any) string, bool) {
fn, ok := h.componentFilterFn[name] return componentFilterFns.Load(name)
return fn, ok
} }
func (h *Handle) AddActionFilter(name string, fns ...func(*Handle, string, ...any) string) { func (h *Handle) AddActionFilter(name string, fns ...func(*Handle, string, ...any) string) {
h.componentFilterFn[name] = append(h.componentFilterFn[name], fns...) v, _ := componentFilterFns.Load(name)
v = append(v, fns...)
componentFilterFns.Store(name, v)
} }
func (h *Handle) DoActionFilter(name, s string, args ...any) string { func (h *Handle) DoActionFilter(name, s string, args ...any) string {
calls, ok := h.componentFilterFn[name] calls, ok := componentFilterFns.Load(name)
if ok { if ok {
return slice.Reduce(calls, func(fn func(*Handle, string, ...any) string, r string) string { return slice.Reduce(calls, func(fn func(*Handle, string, ...any) string, r string) string {
return fn(h, r, args...) return fn(h, r, args...)

View File

@ -40,7 +40,7 @@ func categoryDefaultArgs() map[string]string {
} }
} }
func parseAttr(attr map[any]any) (string, bool) { func parseAttr(attr map[any]any) string {
var attrs []string var attrs []string
class := maps.GetAnyAnyValWithDefaults(attr, "", "className") class := maps.GetAnyAnyValWithDefaults(attr, "", "className")
classes := strings.Split(class, " ") classes := strings.Split(class, " ")
@ -50,7 +50,7 @@ func parseAttr(attr map[any]any) (string, bool) {
} }
style := maps.GetAnyAnyValWithDefaults[map[any]any](attr, nil, "style", "typography") style := maps.GetAnyAnyValWithDefaults[map[any]any](attr, nil, "style", "typography")
if len(style) > 0 { if len(style) > 0 {
styless := maps.AnyAnyMap(style, func(k, v any) (string, string, bool) { styless := maps.AnyAnyMapTo(style, func(k, v any) (string, string, bool) {
kk, ok := k.(string) kk, ok := k.(string)
if !ok { if !ok {
return "", "", false return "", "", false
@ -68,51 +68,64 @@ func parseAttr(attr map[any]any) (string, bool) {
attrs = append(attrs, fmt.Sprintf(`style="%s;"`, strings.Join(styles, ";"))) attrs = append(attrs, fmt.Sprintf(`style="%s;"`, strings.Join(styles, ";")))
} }
attrs = append(attrs, fmt.Sprintf(`class="%s"`, strings.Join(classes, " "))) attrs = append(attrs, fmt.Sprintf(`class="%s"`, strings.Join(classes, " ")))
return strings.Join(attrs, " "), true return strings.Join(attrs, " ")
}
var GetCategoryAttr = reload.BuildValFn("block-category-attr", parseAttr)
var GetCategoryConf = reload.BuildValFnWithConfirm("block-category-conf", categoryConfFn, 5)
func categoryConfFn(blockParser ParserBlock) (map[any]any, bool) {
var con any
err := json.Unmarshal([]byte(blockParser.Attrs), &con)
if err != nil {
logs.Error(err, "解析category attr错误", blockParser.Attrs)
return nil, false
}
var conf map[any]any
switch con.(type) {
case map[any]any:
conf = con.(map[any]any)
case map[string]any:
conf = maps.StrAnyToAnyAny(con.(map[string]any))
}
conf = maps.FilterZeroMerge(categoryConf(), conf)
if maps.GetAnyAnyValWithDefaults(conf, false, "showPostCounts") {
conf["count"] = int64(1)
}
if maps.GetAnyAnyValWithDefaults(conf, false, "displayAsDropdown") {
conf["dropdown"] = int64(1)
}
if maps.GetAnyAnyValWithDefaults(conf, false, "showHierarchy") {
conf["hierarchical"] = int64(1)
}
class := maps.GetAnyAnyValWithDefaults(conf, "", "className")
classes := strings.Split(class, " ")
classes = append(classes, "wp-block-categories")
if conf["dropdown"].(int64) == 1 {
classes = append(classes, "wp-block-categories-dropdown")
conf["className"] = strings.Join(classes, " ")
} else {
classes = append(classes, "wp-block-categories-list")
conf["className"] = strings.Join(classes, " ")
}
return conf, true
}
var GetCategoryArgs = reload.BuildValFnWithAnyParams("block-category-args", categoryArgs)
func categoryArgs(_ ...any) map[string]string {
args := wp.GetComponentsArgs(widgets.Widget, map[string]string{})
return maps.FilterZeroMerge(categoryDefaultArgs(), args)
} }
func Category(h *wp.Handle, id string, blockParser ParserBlock) (func() string, error) { func Category(h *wp.Handle, id string, blockParser ParserBlock) (func() string, error) {
counter := number.Counters[int]() counter := number.Counters[int]()
var err error var err error
conf := reload.GetAnyValBy("block-category-conf", h, func(h *wp.Handle) (map[any]any, bool) { conf := GetCategoryConf(blockParser)
var con any
err = json.Unmarshal([]byte(blockParser.Attrs), &con)
if err != nil {
logs.Error(err, "解析category attr错误", blockParser.Attrs)
return nil, false
}
var conf map[any]any
switch con.(type) {
case map[any]any:
conf = con.(map[any]any)
case map[string]any:
conf = maps.StrAnyToAnyAny(con.(map[string]any))
}
conf = maps.FilterZeroMerge(categoryConf(), conf)
if maps.GetAnyAnyValWithDefaults(conf, false, "showPostCounts") {
conf["count"] = int64(1)
}
if maps.GetAnyAnyValWithDefaults(conf, false, "displayAsDropdown") {
conf["dropdown"] = int64(1)
}
if maps.GetAnyAnyValWithDefaults(conf, false, "showHierarchy") {
conf["hierarchical"] = int64(1)
}
class := maps.GetAnyAnyValWithDefaults(conf, "", "className")
classes := strings.Split(class, " ")
classes = append(classes, "wp-block-categories")
if conf["dropdown"].(int64) == 1 {
classes = append(classes, "wp-block-categories-dropdown")
conf["className"] = strings.Join(classes, " ")
} else {
classes = append(classes, "wp-block-categories-list")
conf["className"] = strings.Join(classes, " ")
}
return conf, true
}, 5)
if err != nil { if err != nil {
return nil, err return nil, err
@ -127,10 +140,7 @@ func Category(h *wp.Handle, id string, blockParser ParserBlock) (func() string,
if maps.GetAnyAnyValWithDefaults(conf, false, "showOnlyTopLevel") { if maps.GetAnyAnyValWithDefaults(conf, false, "showOnlyTopLevel") {
h.C.Set("showOnlyTopLevel", true) h.C.Set("showOnlyTopLevel", true)
} }
args := reload.GetAnyValBys("block-category-args", h, func(h *wp.Handle) (map[string]string, bool) { args := GetCategoryArgs()
args := wp.GetComponentsArgs(h, widgets.Widget, map[string]string{})
return maps.FilterZeroMerge(categoryDefaultArgs(), args), true
})
return func() string { return func() string {
return category(h, id, counter, args, conf) return category(h, id, counter, args, conf)
@ -150,21 +160,21 @@ func category(h *wp.Handle, id string, counter number.Counter[int], args map[str
return str.Join(before, out, args["{$after_widget}"]) return str.Join(before, out, args["{$after_widget}"])
} }
func categoryUl(h *wp.Handle, categories []models.TermsMy, conf map[any]any) string { func categoryUl(h *wp.Handle, categories []models.TermsMy, confAttr map[any]any) string {
s := str.NewBuilder() s := str.NewBuilder()
li := widget.CategoryLi(h, conf, categories) li := widget.CategoryLi(h, confAttr, categories)
attrs := reload.GetAnyValBys("block-category-attr", conf, parseAttr) attrs := GetCategoryAttr(confAttr)
s.Sprintf(`<ul %s>%s</ul>`, attrs, li) s.Sprintf(`<ul %s>%s</ul>`, attrs, li)
return s.String() return s.String()
} }
func dropdown(h *wp.Handle, categories []models.TermsMy, id int, args map[string]string, conf map[any]any) string { func dropdown(h *wp.Handle, categories []models.TermsMy, id int, args map[string]string, confAttr map[any]any) string {
s := str.NewBuilder() s := str.NewBuilder()
ids := fmt.Sprintf(`wp-block-categories-%v`, id) ids := fmt.Sprintf(`wp-block-categories-%v`, id)
args = maps.Copy(args) args = maps.Copy(args)
args["{$selectId}"] = ids args["{$selectId}"] = ids
attrs := reload.GetAnyValBys("block-category-attr", conf, parseAttr) attrs := GetCategoryAttr(confAttr)
selects := widget.DropdownCategories(h, args, conf, categories) selects := widget.DropdownCategories(h, args, confAttr, categories)
s.Sprintf(`<div %s><label class="screen-reader-text" for="%s">%s</label>%s%s</div>`, attrs, ids, args["{$title}"], selects, strings.ReplaceAll(categoryDropdownScript, "{$id}", ids)) s.Sprintf(`<div %s><label class="screen-reader-text" for="%s">%s</label>%s%s</div>`, attrs, ids, args["{$title}"], selects, strings.ReplaceAll(categoryDropdownScript, "{$id}", ids))
return s.String() return s.String()
} }

View File

@ -40,21 +40,29 @@ var archivesConfig = map[any]any{
"title": "归档", "title": "归档",
} }
var GetArchiveConf = BuildconfigFn(archivesConfig, "widget_archives", int64(2))
var GetArchiveArgs = reload.BuildValFnWithAnyParams("", archiveArgsFn)
func archiveArgsFn(a ...any) map[string]string {
h := a[0].(*wp.Handle)
conf := a[1].(map[any]any)
id := a[2].(string)
archiveArgs := archiveArgs()
commonArgs := wp.GetComponentsArgs(widgets.Widget, CommonArgs())
args := wp.GetComponentsArgs(widgets.Archive, archiveArgs)
args = maps.FilterZeroMerge(archiveArgs, CommonArgs(), commonArgs, args)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("archives-", id), str.Join("widget widget_", "archive"))
args["{$title}"] = str.Join(args["{$before_title}"], conf["title"].(string), args["{$after_title}"])
if conf["dropdown"].(int64) == 0 && slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, conf["title"].(string))
args["{$navCloser}"] = "</nav>"
}
return args
}
func Archive(h *wp.Handle, id string) string { func Archive(h *wp.Handle, id string) string {
conf := configs(archivesConfig, "widget_archives", int64(2)) conf := GetArchiveConf()
args := reload.GetAnyValBys("widget-archive-args", h, func(h *wp.Handle) (map[string]string, bool) { args := GetArchiveArgs(h, conf, id)
archiveArgs := archiveArgs()
commonArgs := wp.GetComponentsArgs(h, widgets.Widget, CommonArgs())
args := wp.GetComponentsArgs(h, widgets.Archive, archiveArgs)
args = maps.FilterZeroMerge(archiveArgs, CommonArgs(), commonArgs, args)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("archives-", id), str.Join("widget widget_", "archive"))
args["{$title}"] = str.Join(args["{$before_title}"], conf["title"].(string), args["{$after_title}"])
if conf["dropdown"].(int64) == 0 && slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, conf["title"].(string))
args["{$navCloser}"] = "</nav>"
}
return args, true
})
s := archiveTemplate s := archiveTemplate
if int64(1) == conf["dropdown"].(int64) { if int64(1) == conf["dropdown"].(int64) {
@ -83,11 +91,12 @@ var dropdownScript = `
func archiveDropDown(h *wp.Handle, conf map[any]any, args map[string]string, archives []models.PostArchive) string { func archiveDropDown(h *wp.Handle, conf map[any]any, args map[string]string, archives []models.PostArchive) string {
option := str.NewBuilder() option := str.NewBuilder()
option.Sprintf(`<option value="">%s</option>`, args["{$dropdown_label}"]) option.Sprintf(`<option value="">%s</option>`, args["{$dropdown_label}"])
month := strings.TrimLeft(h.Index.Param.Month, "0") i := h.GetIndexHandle()
month := strings.TrimLeft(i.Param.Month, "0")
showCount := conf["count"].(int64) showCount := conf["count"].(int64)
for _, archive := range archives { for _, archive := range archives {
sel := "" sel := ""
if h.Index.Param.Year == archive.Year && month == archive.Month { if i.Param.Year == archive.Year && month == archive.Month {
sel = "selected" sel = "selected"
} }
count := "" count := ""

View File

@ -44,22 +44,29 @@ func categoryArgs() map[string]string {
} }
} }
var GetCategoryConf = BuildconfigFn(categoryConfig, "widget_categories", int64(2))
var GetCategoryArgs = reload.BuildValFnWithAnyParams("widget-category-args", categoryArgsFn)
func categoryArgsFn(a ...any) map[string]string {
h := a[0].(*wp.Handle)
conf := a[1].(map[any]any)
id := a[2].(string)
commonArgs := wp.GetComponentsArgs(widgets.Widget, map[string]string{})
args := wp.GetComponentsArgs(widgets.Categories, categoryArgs())
args = maps.FilterZeroMerge(categoryArgs(), CommonArgs(), commonArgs, args)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("categories-", id), str.Join("widget widget_", "categories"))
args["{$title}"] = str.Join(args["{$before_title}"], conf["title"].(string), args["{$after_title}"])
if conf["dropdown"].(int64) == 0 && slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, args["{title}"])
args["{$navCloser}"] = "</nav>"
}
return args
}
func Category(h *wp.Handle, id string) string { func Category(h *wp.Handle, id string) string {
conf := configs(categoryConfig, "widget_categories", int64(2)) conf := GetCategoryConf()
args := GetCategoryArgs(h, conf, id)
args := reload.GetAnyValBys("widget-category-args", h, func(h *wp.Handle) (map[string]string, bool) {
commonArgs := wp.GetComponentsArgs(h, widgets.Widget, map[string]string{})
args := wp.GetComponentsArgs(h, widgets.Categories, categoryArgs())
args = maps.FilterZeroMerge(categoryArgs(), CommonArgs(), commonArgs, args)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("categories-", id), str.Join("widget widget_", "categories"))
args["{$title}"] = str.Join(args["{$before_title}"], conf["title"].(string), args["{$after_title}"])
if conf["dropdown"].(int64) == 0 && slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, args["{title}"])
args["{$navCloser}"] = "</nav>"
}
return args, true
})
t := categoryTemplate t := categoryTemplate
dropdown := conf["dropdown"].(int64) dropdown := conf["dropdown"].(int64)
categories := cache.CategoriesTags(h.C, constraints.Category) categories := cache.CategoriesTags(h.C, constraints.Category)
@ -201,8 +208,9 @@ func DropdownCategories(h *wp.Handle, args map[string]string, conf map[any]any,
s.Sprintf(` <option value="-1">%s</option> s.Sprintf(` <option value="-1">%s</option>
`, args["{$show_option_none}"]) `, args["{$show_option_none}"])
currentCategory := "" currentCategory := ""
i := h.GetIndexHandle()
if h.Scene() == constraints.Category { if h.Scene() == constraints.Category {
currentCategory = h.Index.Param.Category currentCategory = i.Param.Category
} }
showCount := conf["count"].(int64) showCount := conf["count"].(int64)
fn := func(category models.TermsMy, deep int) { fn := func(category models.TermsMy, deep int) {
@ -235,7 +243,7 @@ func DropdownCategories(h *wp.Handle, args map[string]string, conf map[any]any,
} }
func IsCategory(h *wp.Handle) (category models.TermsMy, r bool) { func IsCategory(h *wp.Handle) (category models.TermsMy, r bool) {
cate := wp.GetComponentsArgs[map[string]string](h, widgets.Categories, categoryArgs()) cate := wp.GetComponentsArgs[map[string]string](widgets.Categories, categoryArgs())
name, ok := cate["{$name}"] name, ok := cate["{$name}"]
if !ok || name == "" { if !ok || name == "" {
return return
@ -260,7 +268,7 @@ func IsCategory(h *wp.Handle) (category models.TermsMy, r bool) {
} }
func CategoryQueryName(h *wp.Handle) string { func CategoryQueryName(h *wp.Handle) string {
cate := wp.GetComponentsArgs[map[string]string](h, widgets.Categories, categoryArgs()) cate := wp.GetComponentsArgs[map[string]string](widgets.Categories, categoryArgs())
name, ok := cate["{$name}"] name, ok := cate["{$name}"]
if ok { if ok {
return name return name

View File

@ -14,9 +14,13 @@ func Fn(id string, fn func(*wp.Handle, string) string) func(h *wp.Handle) string
} }
} }
func configs[M ~map[K]V, K comparable, V any](m M, key string, a ...any) M { func configFns[K comparable, V any](m map[K]V, key string, a ...any) func(_ ...any) map[K]V {
return reload.GetAnyValBys(str.Join("widget-config-", key), key, func(_ string) (M, bool) { return func(_ ...any) map[K]V {
c := wpconfig.GetPHPArrayVal[M](key, nil, a...) c := wpconfig.GetPHPArrayVal[map[K]V](key, nil, a...)
return maps.FilterZeroMerge(maps.Copy(m), c), true return maps.FilterZeroMerge(maps.Copy(m), c)
}) }
}
func BuildconfigFn[K comparable, V any](m map[K]V, key string, a ...any) func(_ ...any) map[K]V {
return reload.BuildValFnWithAnyParams(str.Join("widget-config-", key), configFns(m, key, a...))
} }

View File

@ -21,34 +21,39 @@ var metaTemplate = `{$before_widget}
{$navCloser} {$navCloser}
{$after_widget}` {$after_widget}`
func metaArgs() map[string]string { func defaultMetaArgs() map[string]string {
return map[string]string{ return map[string]string{
"{$aria_label}": "", "{$aria_label}": "",
"{$title}": "", "{$title}": "",
} }
} }
func Meta(h *wp.Handle, id string) string { var GetMetaArgs = reload.BuildValFnWithAnyParams("widget-meta-args", ParseMetaArgs)
args := reload.GetAnyValBys("widget-meta-args", h, func(h *wp.Handle) (map[string]string, bool) {
commonArgs := wp.GetComponentsArgs(h, widgets.Widget, map[string]string{})
metaArgs := metaArgs()
args := wp.GetComponentsArgs(h, widgets.Meta, metaArgs)
args = maps.FilterZeroMerge(metaArgs, CommonArgs(), commonArgs, args)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("meta-", id), str.Join("widget widget_", "meta"))
args["{$title}"] = wpconfig.GetPHPArrayVal("widget_meta", "其它操作", int64(2), "title")
if args["{$title}"] == "" {
args["{$title}"] = "其他操作"
}
if args["{$title}"] != "" {
args["{$h2title}"] = str.Join(args["{$before_title}"], args["{$title}"], args["{$after_title}"])
}
if slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, args["{$title}"])
args["{$navCloser}"] = "</nav>"
}
return args, true
})
func ParseMetaArgs(a ...any) map[string]string {
h := a[0].(*wp.Handle)
id := a[1].(string)
commonArgs := wp.GetComponentsArgs(widgets.Widget, map[string]string{})
metaArgs := defaultMetaArgs()
args := wp.GetComponentsArgs(widgets.Meta, metaArgs)
args = maps.FilterZeroMerge(metaArgs, CommonArgs(), commonArgs, args)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("meta-", id), str.Join("widget widget_", "meta"))
args["{$title}"] = wpconfig.GetPHPArrayVal("widget_meta", "其它操作", int64(2), "title")
if args["{$title}"] == "" {
args["{$title}"] = "其他操作"
}
if args["{$title}"] != "" {
args["{$h2title}"] = str.Join(args["{$before_title}"], args["{$title}"], args["{$after_title}"])
}
if slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, args["{$title}"])
args["{$navCloser}"] = "</nav>"
}
return args
}
func Meta(h *wp.Handle, id string) string {
args := GetMetaArgs(h, id)
ss := str.NewBuilder() ss := str.NewBuilder()
if str.ToInteger(wpconfig.GetOption("users_can_register"), 0) > 0 { if str.ToInteger(wpconfig.GetOption("users_can_register"), 0) > 0 {
ss.Sprintf(`<li><a href="/wp-login.php?action=register">注册</li>`) ss.Sprintf(`<li><a href="/wp-login.php?action=register">注册</li>`)

View File

@ -39,22 +39,29 @@ var recentCommentsTemplate = `{$before_widget}
{$after_widget} {$after_widget}
` `
func RecentComments(h *wp.Handle, id string) string { var GetRecentCommentConf = BuildconfigFn(recentCommentConf, "widget_recent-comments", int64(2))
conf := configs(recentCommentConf, "widget_recent-comments", int64(2))
args := reload.GetAnyValBys("widget-recent-comment-args", h, func(h *wp.Handle) (map[string]string, bool) { var GetRecentCommentArgs = reload.BuildValFnWithAnyParams("widget-recent-comment-args", RecentCommentArgs)
commentsArgs := recentCommentsArgs()
commonArgs := wp.GetComponentsArgs(h, widgets.Widget, map[string]string{}) func RecentCommentArgs(a ...any) map[string]string {
args := wp.GetComponentsArgs(h, widgets.RecentComments, commentsArgs) h := a[0].(*wp.Handle)
args = maps.FilterZeroMerge(commentsArgs, CommonArgs(), commonArgs, args) conf := a[1].(map[any]any)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("recent-comments-", id), str.Join("widget widget_", "recent_comments")) id := a[2].(string)
args["{$title}"] = str.Join(args["{$before_title}"], conf["title"].(string), args["{$after_title}"]) commentsArgs := recentCommentsArgs()
if slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") { commonArgs := wp.GetComponentsArgs(widgets.Widget, map[string]string{})
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, conf["title"]) args := wp.GetComponentsArgs(widgets.RecentComments, commentsArgs)
args["{$navCloser}"] = "</nav>" args = maps.FilterZeroMerge(commentsArgs, CommonArgs(), commonArgs, args)
} args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("recent-comments-", id), str.Join("widget widget_", "recent_comments"))
return args, true args["{$title}"] = str.Join(args["{$before_title}"], conf["title"].(string), args["{$after_title}"])
}) if slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, conf["title"])
args["{$navCloser}"] = "</nav>"
}
return args
}
func RecentComments(h *wp.Handle, id string) string {
conf := GetRecentCommentConf()
args := GetRecentCommentArgs(h, conf, id)
comments := slice.Map(cache.RecentComments(h.C, int(conf["number"].(int64))), func(t models.Comments) string { comments := slice.Map(cache.RecentComments(h.C, int(conf["number"].(int64))), func(t models.Comments) string {
return fmt.Sprintf(` <li> return fmt.Sprintf(` <li>

View File

@ -25,7 +25,7 @@ var recentPostsTemplate = `{$before_widget}
{$after_widget} {$after_widget}
` `
func recentPostsArgs() map[string]string { func DefaultRecentPostsArgs() map[string]string {
return map[string]string{ return map[string]string{
"{$before_sidebar}": "", "{$before_sidebar}": "",
"{$after_sidebar}": "", "{$after_sidebar}": "",
@ -35,7 +35,7 @@ func recentPostsArgs() map[string]string {
} }
} }
func recentConf() map[any]any { func DefaultRecentConf() map[any]any {
return map[any]any{ return map[any]any{
"number": int64(5), "number": int64(5),
"show_date": false, "show_date": false,
@ -43,28 +43,37 @@ func recentConf() map[any]any {
} }
} }
var GetRecentPostConf = reload.BuildValFnWithAnyParams("widget-recent-posts-conf", RecentPostConf)
func RecentPostConf(_ ...any) map[any]any {
recent := DefaultRecentConf()
conf := wpconfig.GetPHPArrayVal[map[any]any]("widget_recent-posts", recent, int64(2))
conf = maps.FilterZeroMerge(recent, conf)
return conf
}
var GetRecentPostArgs = reload.BuildValFnWithAnyParams("widget-recent-posts-args", ParseRecentPostArgs)
func ParseRecentPostArgs(a ...any) map[string]string {
h := a[0].(*wp.Handle)
conf := a[1].(map[any]any)
id := a[2].(string)
recent := DefaultRecentPostsArgs()
commonArgs := wp.GetComponentsArgs(widgets.Widget, map[string]string{})
args := wp.GetComponentsArgs(widgets.RecentPosts, recent)
args = maps.FilterZeroMerge(recent, CommonArgs(), commonArgs, args)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("recent-posts-", id), str.Join("widget widget_", "recent_entries"))
args["{$title}"] = str.Join(args["{$before_title}"], conf["title"].(string), args["{$after_title}"])
if slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, conf["title"])
args["{$navCloser}"] = "</nav>"
}
return args
}
func RecentPosts(h *wp.Handle, id string) string { func RecentPosts(h *wp.Handle, id string) string {
conf := reload.GetAnyValBys("widget-recent-posts-conf", h, func(h *wp.Handle) (map[any]any, bool) { conf := GetRecentPostConf()
recent := recentConf() args := GetRecentPostArgs(h, conf, id)
conf := wpconfig.GetPHPArrayVal[map[any]any]("widget_recent-posts", recent, int64(2))
conf = maps.FilterZeroMerge(recent, conf)
return conf, true
})
args := reload.GetAnyValBys("widget-recent-posts-args", h, func(h *wp.Handle) (map[string]string, bool) {
recent := recentPostsArgs()
commonArgs := wp.GetComponentsArgs(h, widgets.Widget, map[string]string{})
args := wp.GetComponentsArgs(h, widgets.RecentPosts, recent)
args = maps.FilterZeroMerge(recent, CommonArgs(), commonArgs, args)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("recent-posts-", id), str.Join("widget widget_", "recent_entries"))
args["{$title}"] = str.Join(args["{$before_title}"], conf["title"].(string), args["{$after_title}"])
if slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
args["{$nav}"] = fmt.Sprintf(`<nav aria-label="%s">`, conf["title"])
args["{$navCloser}"] = "</nav>"
}
return args, true
})
currentPostId := uint64(0) currentPostId := uint64(0)
if h.Scene() == constraints.Detail { if h.Scene() == constraints.Detail {
currentPostId = str.ToInteger(h.C.Param("id"), uint64(0)) currentPostId = str.ToInteger(h.C.Param("id"), uint64(0))

View File

@ -47,34 +47,40 @@ func searchArgs() map[string]string {
var form = html5SearchForm var form = html5SearchForm
var GetSearchArgs = reload.BuildValFnWithAnyParams("widget-search-args", ParseSearchArgs)
func ParseSearchArgs(a ...any) map[string]string {
h := a[0].(*wp.Handle)
id := a[1].(string)
search := searchArgs()
commonArgs := wp.GetComponentsArgs(widgets.Widget, map[string]string{})
args := wp.GetComponentsArgs(widgets.Search, search)
args = maps.FilterZeroMerge(search, CommonArgs(), commonArgs, args)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("search-", id), str.Join("widget widget_", "search"))
if args["{$title}"] == "" {
args["{$title}"] = wpconfig.GetPHPArrayVal("widget_search", "", int64(2), "title")
}
if args["{$title}"] != "" {
args["{$title}"] = str.Join(args["{$before_title}"], args["{$title}"], args["{$after_title}"])
}
if args["{$form}"] != "" {
form = args["{$form}"]
delete(args, "{$form}")
}
if !slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
form = xmlSearchForm
}
return args
}
func Search(h *wp.Handle, id string) string { func Search(h *wp.Handle, id string) string {
args := reload.GetAnyValBys("widget-search-args", h, func(h *wp.Handle) (map[string]string, bool) { args := GetSearchArgs(h, id)
search := searchArgs()
commonArgs := wp.GetComponentsArgs(h, widgets.Widget, map[string]string{})
args := wp.GetComponentsArgs(h, widgets.Search, search)
args = maps.FilterZeroMerge(search, CommonArgs(), commonArgs, args)
args["{$before_widget}"] = fmt.Sprintf(args["{$before_widget}"], str.Join("search-", id), str.Join("widget widget_", "search"))
if args["{$title}"] == "" {
args["{$title}"] = wpconfig.GetPHPArrayVal("widget_search", "", int64(2), "title")
}
if args["{$title}"] != "" {
args["{$title}"] = str.Join(args["{$before_title}"], args["{$title}"], args["{$after_title}"])
}
if args["{$form}"] != "" {
form = args["{$form}"]
delete(args, "{$form}")
}
if !slice.IsContained(h.CommonThemeMods().ThemeSupport.HTML5, "navigation-widgets") {
form = xmlSearchForm
}
return args, true
})
s := strings.ReplaceAll(searchTemplate, "{$form}", form) s := strings.ReplaceAll(searchTemplate, "{$form}", form)
val := "" val := ""
if h.Scene() == constraints.Search { if h.Scene() == constraints.Search {
val = html.SpecialChars(h.Index.Param.Search) val = html.SpecialChars(h.GetIndexHandle().Param.Search)
} }
s = strings.ReplaceAll(s, "{$value}", val) s = strings.ReplaceAll(s, "{$value}", val)
return h.DoActionFilter(widgets.Search, str.Replace(s, args)) return h.DoActionFilter(widgets.Search, str.Replace(s, args))

View File

@ -18,16 +18,21 @@ func (h *Handle) DisplayHeaderText() bool {
return h.themeMods.ThemeSupport.CustomHeader.HeaderText && "blank" != h.themeMods.HeaderTextcolor return h.themeMods.ThemeSupport.CustomHeader.HeaderText && "blank" != h.themeMods.HeaderTextcolor
} }
var GetCustomHeaderImgFn = reload.BuildValFnWithConfirm("headerImages", customHeadImag, 5)
func customHeadImag(h *Handle) ([]models.PostThumbnail, bool) {
hs, err := h.GetHeaderImages(h.theme)
if err != nil {
h.SetErr(err)
return nil, false
}
return hs, true
}
func (h *Handle) GetCustomHeaderImg() (r models.PostThumbnail, isRand bool) { func (h *Handle) GetCustomHeaderImg() (r models.PostThumbnail, isRand bool) {
var err error var err error
img := reload.GetAnyValBy("headerImages", h.theme, func(theme string) ([]models.PostThumbnail, bool) { img := GetCustomHeaderImgFn(h)
hs, er := h.GetHeaderImages(h.theme) err = h.Err()
if er != nil {
err = er
return nil, false
}
return hs, true
}, 5)
if err != nil { if err != nil {
logs.Error(err, "获取页眉背景图失败") logs.Error(err, "获取页眉背景图失败")
return return

View File

@ -42,10 +42,10 @@ func CalCustomLogo(h *Handle) (r string) {
return return
} }
var GetCustomLog = reload.BuildValFn("customLogo", CalCustomLogo)
func customLogo(h *Handle) func() string { func customLogo(h *Handle) func() string {
return func() string { return func() string {
return reload.GetAnyValBys("customLogo", h, func(h *Handle) (string, bool) { return GetCustomLog(h)
return CalCustomLogo(h), true
})
} }
} }

View File

@ -78,6 +78,15 @@ func (d *DetailHandle) PasswordProject() {
} }
} }
} }
func (h *Handle) GetDetailHandle() *DetailHandle {
v, ok := h.C.Get("detailHandle")
if !ok {
vv := NewDetailHandle(h)
h.C.Set("detailHandle", vv)
return vv
}
return v.(*DetailHandle)
}
func (d *DetailHandle) CommentData() { func (d *DetailHandle) CommentData() {
d.ginH["totalCommentNum"] = 0 d.ginH["totalCommentNum"] = 0
d.ginH["totalCommentPage"] = 1 d.ginH["totalCommentPage"] = 1
@ -170,16 +179,17 @@ func DetailRender(h *Handle) {
if h.Stats != constraints.Ok { if h.Stats != constraints.Ok {
return return
} }
d := h.Detail d := h.GetDetailHandle()
d.PasswordProject() d.PasswordProject()
d.RenderComment() d.RenderComment()
d.ginH["post"] = d.Post d.ginH["post"] = d.Post
} }
func Detail(h *Handle) { func Detail(h *Handle) {
err := h.Detail.BuildDetailData() d := h.GetDetailHandle()
err := d.BuildDetailData()
if err != nil { if err != nil {
h.Detail.SetErr(err) d.SetErr(err)
} }
h.SetData("scene", h.Scene()) h.SetData("scene", h.Scene())
} }
@ -187,7 +197,7 @@ func Detail(h *Handle) {
func ReplyCommentJs(h *Handle) { func ReplyCommentJs(h *Handle) {
h.PushFooterScript(constraints.Detail, NewComponent("comment-reply.js", "", false, 10, func(h *Handle) string { h.PushFooterScript(constraints.Detail, NewComponent("comment-reply.js", "", false, 10, func(h *Handle) string {
reply := "" reply := ""
if h.Detail.Post.CommentStatus == "open" && wpconfig.GetOption("thread_comments") == "1" { if h.GetDetailHandle().Post.CommentStatus == "open" && wpconfig.GetOption("thread_comments") == "1" {
reply = `<script src='/wp-includes/js/comment-reply.min.js' id='comment-reply-js'></script>` reply = `<script src='/wp-includes/js/comment-reply.min.js' id='comment-reply-js'></script>`
} }
return reply return reply

View File

@ -25,6 +25,16 @@ type IndexHandle struct {
postsPlugin PostsPlugin postsPlugin PostsPlugin
} }
func (h *Handle) GetIndexHandle() *IndexHandle {
v, ok := h.C.Get("indexHandle")
if !ok {
vv := NewIndexHandle(h)
h.C.Set("indexHandle", vv)
return vv
}
return v.(*IndexHandle)
}
func (i *IndexHandle) ListPlugin() func(*Handle, *models.Posts) { func (i *IndexHandle) ListPlugin() func(*Handle, *models.Posts) {
return i.postsPlugin return i.postsPlugin
} }
@ -120,8 +130,11 @@ func (i *IndexHandle) Pagination() {
} }
func (i *IndexHandle) BuildIndexData(parm *IndexParams) (err error) { func (i *IndexHandle) BuildIndexData() (err error) {
err = i.ParseIndex(parm) if i.Param == nil {
i.Param = NewIndexParams(i.C)
}
err = i.ParseIndex(i.Param)
if err != nil { if err != nil {
i.Stats = constraints.ParamError i.Stats = constraints.ParamError
return return
@ -137,12 +150,12 @@ func (i *IndexHandle) BuildIndexData(parm *IndexParams) (err error) {
return return
} }
var GetPostsPlugin = reload.BuildValFnWithAnyParams("postPlugins", UsePostsPlugins)
func (i *IndexHandle) ExecPostsPlugin() { func (i *IndexHandle) ExecPostsPlugin() {
fn := i.postsPlugin fn := i.postsPlugin
if fn == nil { if fn == nil {
fn = reload.GetAnyValBys("postPlugins", i, func(a *IndexHandle) (PostsPlugin, bool) { fn = GetPostsPlugin()
return UsePostsPlugins(), true
})
} }
for j := range i.Posts { for j := range i.Posts {
fn(i.Handle, &i.Posts[j]) fn(i.Handle, &i.Posts[j])
@ -150,15 +163,15 @@ func (i *IndexHandle) ExecPostsPlugin() {
} }
func IndexRender(h *Handle) { func IndexRender(h *Handle) {
i := h.Index i := h.GetIndexHandle()
i.ExecPostsPlugin() i.ExecPostsPlugin()
i.Pagination() i.Pagination()
i.ginH["posts"] = i.Posts i.ginH["posts"] = i.Posts
} }
func Index(h *Handle) { func Index(h *Handle) {
i := h.Index i := h.GetIndexHandle()
err := i.BuildIndexData(NewIndexParams(i.C)) err := i.BuildIndexData()
if err != nil { if err != nil {
i.SetErr(err) i.SetErr(err)
} }
@ -166,11 +179,11 @@ func Index(h *Handle) {
} }
func (i *IndexHandle) MarkSticky(posts *[]models.Posts) { func (i *IndexHandle) MarkSticky(posts *[]models.Posts) {
a := i.StickPosts() a := GetStickPosts(i.Handle)
if len(a) < 1 { if len(a) < 1 {
return return
} }
m := i.StickMapPosts() m := GetStickMapPosts(i.Handle)
*posts = append(a, slice.Filter(*posts, func(post models.Posts, _ int) bool { *posts = append(a, slice.Filter(*posts, func(post models.Posts, _ int) bool {
_, ok := m[post.Id] _, ok := m[post.Id]
return !ok return !ok

View File

@ -69,7 +69,7 @@ func PostPlugin(calls ...PostsPlugin) PostsPlugin {
} }
} }
func UsePostsPlugins() PostsPlugin { func UsePostsPlugins(_ ...any) PostsPlugin {
m := pluginFns.Load() m := pluginFns.Load()
pluginss := slice.FilterAndMap(config.GetConfig().ListPagePlugins, func(t string) (func(PostsPlugin, *Handle, *models.Posts), bool) { pluginss := slice.FilterAndMap(config.GetConfig().ListPagePlugins, func(t string) (func(PostsPlugin, *Handle, *models.Posts), bool) {
f, ok := m[t] f, ok := m[t]

View File

@ -71,14 +71,7 @@ var plainRouteParam = reload.Vars([]Plain{
if u == "" { if u == "" {
return false return false
} }
users := reload.GetAnyValBys("usersIds", struct{}{}, users := GetUsersIds(h)
func(_ struct{}) (map[uint64]string, bool) {
users, err := cache.GetAllUsername(h.C)
if err != nil {
return nil, true
}
return maps.Flip(users), true
})
name, ok := users[str.ToInteger[uint64](u, 0)] name, ok := users[str.ToInteger[uint64](u, 0)]
if !ok { if !ok {
return false return false
@ -90,6 +83,14 @@ var plainRouteParam = reload.Vars([]Plain{
}, },
}) })
var GetUsersIds = reload.BuildValFnWithConfirm("usersIds", func(h *wp.Handle) (map[uint64]string, bool) {
users, err := cache.GetAllUsername(h.C)
if err != nil {
return nil, false
}
return maps.Flip(users), true
}, 10)
func SetExplainRouteParam(p []Plain) { func SetExplainRouteParam(p []Plain) {
plainRouteParam.Store(p) plainRouteParam.Store(p)
} }

View File

@ -3,7 +3,6 @@ package wp
import ( import (
"github.com/fthvgb1/wp-go/app/pkg/constraints" "github.com/fthvgb1/wp-go/app/pkg/constraints"
"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/slice" "github.com/fthvgb1/wp-go/helper/slice"
str "github.com/fthvgb1/wp-go/helper/strings" str "github.com/fthvgb1/wp-go/helper/strings"
) )
@ -52,10 +51,12 @@ func (h *Handle) ReplacePipe(scene, pipeName string, pipe Pipe) error {
} }
func (h *Handle) PushHandler(pipScene string, scene string, fns ...HandleCall) { func (h *Handle) PushHandler(pipScene string, scene string, fns ...HandleCall) {
if _, ok := h.handlers[pipScene]; !ok { v, ok := handlerss.Load(pipScene)
h.handlers[pipScene] = make(map[string][]HandleCall) if !ok {
v = make(map[string][]HandleCall)
} }
h.handlers[pipScene][scene] = append(h.handlers[pipScene][scene], fns...) v[scene] = append(v[scene], fns...)
handlerss.Store(pipScene, v)
} }
func (h *Handle) PushRender(statsOrScene string, fns ...HandleCall) { func (h *Handle) PushRender(statsOrScene string, fns ...HandleCall) {
@ -65,27 +66,14 @@ func (h *Handle) PushDataHandler(scene string, fns ...HandleCall) {
h.PushHandler(constraints.PipeData, scene, fns...) h.PushHandler(constraints.PipeData, scene, fns...)
} }
func BuildPipe(pipeScene string, keyFn func(*Handle, string) string, fn func(*Handle, map[string][]HandleCall, string) []HandleCall) func(HandleFn[*Handle], *Handle) { func BuildHandlers(pipeScene string, keyFn func(*Handle, string) string,
fn func(*Handle, map[string][]HandleCall, string) []HandleCall) func(HandleFn[*Handle], *Handle) {
pipeHandlerFn := reload.BuildMapFn[string]("pipeHandlers", BuildHandler(pipeScene, keyFn, fn))
return func(next HandleFn[*Handle], h *Handle) { return func(next HandleFn[*Handle], h *Handle) {
key := keyFn(h, pipeScene) key := keyFn(h, pipeScene)
handlers := reload.GetAnyValMapBy("pipeHandlers", key, h, func(h *Handle) ([]HandleCall, bool) { handlers := pipeHandlerFn(key, h)
conf := h.handleHook[pipeScene]
calls := fn(h, h.handlers[pipeScene], key)
calls = slice.FilterAndMap(calls, func(call HandleCall) (HandleCall, bool) {
ok := true
for _, hook := range conf {
call, ok = hook(call)
if !ok {
break
}
}
return call, ok
})
slice.SimpleSort(calls, slice.DESC, func(t HandleCall) float64 {
return t.Order
})
return calls, true
})
for _, handler := range handlers { for _, handler := range handlers {
handler.Fn(h) handler.Fn(h)
if h.abort { if h.abort {
@ -98,25 +86,58 @@ func BuildPipe(pipeScene string, keyFn func(*Handle, string) string, fn func(*Ha
} }
} }
func BuildHandler(pipeScene string, keyFn func(*Handle, string) string,
fn func(*Handle, map[string][]HandleCall, string) []HandleCall) func(*Handle) []HandleCall {
return func(h *Handle) []HandleCall {
key := keyFn(h, pipeScene)
mut := reload.GetGlobeMutex()
mut.Lock()
hookers, _ := handleHooks.Load(pipeScene)
hh, _ := handlerss.Load(pipeScene)
mut.Unlock()
calls := fn(h, hh, key)
calls = slice.FilterAndMap(calls, func(call HandleCall) (HandleCall, bool) {
ok := true
for _, hook := range hookers {
call, ok = hook(call)
if !ok {
break
}
}
return call, ok
})
slice.SimpleSort(calls, slice.DESC, func(t HandleCall) float64 {
return t.Order
})
return calls
}
}
func PipeKey(h *Handle, pipScene string) string { func PipeKey(h *Handle, pipScene string) string {
key := str.Join("pipekey", "-", pipScene, "-", h.scene, "-", h.Stats) key := str.Join("pipekey", "-", pipScene, "-", h.scene, "-", h.Stats)
return h.DoActionFilter("pipeKey", key, pipScene) return h.DoActionFilter("pipeKey", key, pipScene)
} }
var pipeInitFn = reload.BuildMapFn[string]("pipeInit", BuildPipe)
func Run(h *Handle, conf func(*Handle)) { func Run(h *Handle, conf func(*Handle)) {
if !helper.GetContextVal(h.C, "inited", false) { if !h.isInited {
InitHandle(conf, h) InitHandle(conf, h)
} }
reload.GetAnyValBys(str.Join("pipeInit-", h.scene), h, BuildPipeAndHandler)(h) pipeInitFn(h.scene, h.scene)(h)
} }
func BuildPipeAndHandler(h *Handle) (func(*Handle), bool) { func BuildPipe(scene string) func(*Handle) {
p := GetFn[Pipe]("pipe", constraints.AllScene) pipees := GetFn[Pipe]("pipe", constraints.AllScene)
p = append(p, GetFn[Pipe]("pipe", h.scene)...) pipees = append(pipees, GetFn[Pipe]("pipe", scene)...)
pipes := slice.FilterAndMap(p, func(pipe Pipe) (Pipe, bool) { pipes := slice.FilterAndMap(pipees, func(pipe Pipe) (Pipe, bool) {
var ok bool var ok bool
mut := reload.GetGlobeMutex()
mut.Lock()
hooks := GetFnHook[func(Pipe) (Pipe, bool)]("pipeHook", constraints.AllScene) hooks := GetFnHook[func(Pipe) (Pipe, bool)]("pipeHook", constraints.AllScene)
hooks = append(hooks, GetFnHook[func(Pipe) (Pipe, bool)]("pipeHook", h.scene)...) hooks = append(hooks, GetFnHook[func(Pipe) (Pipe, bool)]("pipeHook", scene)...)
mut.Unlock()
for _, fn := range hooks { for _, fn := range hooks {
pipe, ok = fn(pipe) pipe, ok = fn(pipe)
if !ok { if !ok {
@ -132,7 +153,7 @@ func BuildPipeAndHandler(h *Handle) (func(*Handle), bool) {
arr := slice.Map(pipes, func(t Pipe) HandlePipeFn[*Handle] { arr := slice.Map(pipes, func(t Pipe) HandlePipeFn[*Handle] {
return t.Fn return t.Fn
}) })
return HandlePipe(NothingToDo, arr...), true return HandlePipe(NothingToDo, arr...)
} }
func MiddlewareKey(h *Handle, pipScene string) string { func MiddlewareKey(h *Handle, pipScene string) string {
@ -164,24 +185,30 @@ func PipeRender(h *Handle, renders map[string][]HandleCall, key string) (handler
// DeleteHandle 写插件的时候用 // DeleteHandle 写插件的时候用
func (h *Handle) DeleteHandle(pipeScene string, name string) { func (h *Handle) DeleteHandle(pipeScene string, name string) {
h.handleHook[pipeScene] = append(h.handleHook[pipeScene], func(call HandleCall) (HandleCall, bool) { v, _ := handleHooks.Load(pipeScene)
v = append(v, func(call HandleCall) (HandleCall, bool) {
return call, name != call.Name return call, name != call.Name
}) })
handleHooks.Store(pipeScene, v)
} }
// ReplaceHandle 写插件的时候用 // ReplaceHandle 写插件的时候用
func (h *Handle) ReplaceHandle(pipeScene, name string, fn HandleFn[*Handle]) { func (h *Handle) ReplaceHandle(pipeScene, name string, fn HandleFn[*Handle]) {
h.handleHook[pipeScene] = append(h.handleHook[pipeScene], func(call HandleCall) (HandleCall, bool) { v, _ := handleHooks.Load(pipeScene)
v = append(v, func(call HandleCall) (HandleCall, bool) {
if name == call.Name { if name == call.Name {
call.Fn = fn call.Fn = fn
} }
return call, true return call, true
}) })
handleHooks.Store(pipeScene, v)
} }
// HookHandle 写插件的时候用 // HookHandle 写插件的时候用
func (h *Handle) HookHandle(pipeScene string, hook func(HandleCall) (HandleCall, bool)) { func (h *Handle) HookHandle(pipeScene string, hook func(HandleCall) (HandleCall, bool)) {
h.handleHook[pipeScene] = append(h.handleHook[pipeScene], hook) v, _ := handleHooks.Load(pipeScene)
v = append(v, hook)
handleHooks.Store(pipeScene, v)
} }
func (h *Handle) PushPipeHandleHook(name string, fn ...func([]HandleCall) []HandleCall) error { func (h *Handle) PushPipeHandleHook(name string, fn ...func([]HandleCall) []HandleCall) error {
@ -197,10 +224,10 @@ func (h *Handle) PipeHandleHook(name string, calls []HandleCall, m map[string][]
func InitPipe(h *Handle) { func InitPipe(h *Handle) {
h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeMiddleware, 300, h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeMiddleware, 300,
BuildPipe(constraints.PipeMiddleware, MiddlewareKey, PipeMiddlewareHandle))) BuildHandlers(constraints.PipeMiddleware, MiddlewareKey, PipeMiddlewareHandle)))
h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeData, 200, h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeData, 200,
BuildPipe(constraints.PipeData, PipeKey, PipeDataHandle))) BuildHandlers(constraints.PipeData, PipeKey, PipeDataHandle)))
h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeRender, 100, h.PushPipe(constraints.AllScene, NewPipe(constraints.PipeRender, 100,
BuildPipe(constraints.PipeRender, PipeKey, PipeRender))) BuildHandlers(constraints.PipeRender, PipeKey, PipeRender)))
} }

View File

@ -70,49 +70,51 @@ func Hook(path string, fn func(Route) Route) {
return r, path == r.Path return r, path == r.Path
}) })
} }
var RegRouteFn = reload.BuildValFnWithAnyParams("regexRoute", RegRouteHook)
func RegRouteHook(_ ...any) 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 {
continue
}
m[v.Path] = v
if v.Type != "reg" {
continue
}
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
}
}
func ResolveRoute(h *wp.Handle) { func ResolveRoute(h *wp.Handle) {
requestURI := h.C.Request.RequestURI requestURI := h.C.Request.RequestURI
rs, rrs := reload.GetAnyValBys("route", rs, rrs := RegRouteFn()()
struct{}{},
func(_ struct{}) (func() (map[string]Route, map[string]*regexp.Regexp), bool) {
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 {
continue
}
m[v.Path] = v
if v.Type != "reg" {
continue
}
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
}, true
})()
v, ok := rs[requestURI] v, ok := rs[requestURI]
if ok && slice.IsContained(v.Method, h.C.Request.Method) { if ok && slice.IsContained(v.Method, h.C.Request.Method) {
h.SetScene(v.Scene) h.SetScene(v.Scene)
wp.Run(h, nil) wp.Run(h, nil)
h.Abort()
return return
} }
for path, reg := range rrs { for path, reg := range rrs {
@ -125,6 +127,7 @@ func ResolveRoute(h *wp.Handle) {
h.SetScene(rr.Scene) h.SetScene(rr.Scene)
h.C.Set("route", r) h.C.Set("route", r)
wp.Run(h, nil) wp.Run(h, nil)
h.Abort()
return return
} }
} }

View File

@ -8,41 +8,41 @@ import (
"github.com/fthvgb1/wp-go/app/pkg/models" "github.com/fthvgb1/wp-go/app/pkg/models"
"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/maps"
"github.com/fthvgb1/wp-go/helper/slice" "github.com/fthvgb1/wp-go/helper/slice"
str "github.com/fthvgb1/wp-go/helper/strings" str "github.com/fthvgb1/wp-go/helper/strings"
) )
func (h *Handle) StickPosts() []models.Posts { var GetStickPosts = reload.BuildValFnWithConfirm("stickPostsSlice", ParseStickPosts)
return reload.GetAnyValBys("stickPostsSlice", h, func(h *Handle) (r []models.Posts, ok bool) {
v := wpconfig.GetOption("sticky_posts") func ParseStickPosts(h *Handle) (r []models.Posts, ok bool) {
if v == "" { v := wpconfig.GetOption("sticky_posts")
return if v == "" {
}
array, err := phpserialize.UnmarshalIndexedArray([]byte(v))
if err != nil {
logs.Error(err, "解析option sticky_posts错误", v)
return
}
r = slice.FilterAndMap(array, func(t any) (models.Posts, bool) {
id := str.ToInt[uint64](fmt.Sprintf("%v", t))
post, err := cache.GetPostById(h.C, id)
post.IsSticky = true
return post, err == nil
})
ok = true
return return
}
array, err := phpserialize.UnmarshalIndexedArray([]byte(v))
if err != nil {
logs.Error(err, "解析option sticky_posts错误", v)
return
}
r = slice.FilterAndMap(array, func(t any) (models.Posts, bool) {
id := str.ToInt[uint64](fmt.Sprintf("%v", t))
post, err := cache.GetPostById(h.C, id)
post.IsSticky = true
return post, err == nil
}) })
ok = true
return
} }
func (h *Handle) StickMapPosts() map[uint64]models.Posts { var GetStickMapPosts = reload.BuildValFn("stickPostsMap", StickMapPosts)
return reload.GetAnyValBys("stickPostsMap", h, func(h *Handle) (map[uint64]models.Posts, bool) {
return slice.SimpleToMap(h.StickPosts(), func(v models.Posts) uint64 { func StickMapPosts(h *Handle) map[uint64]models.Posts {
return v.Id return slice.SimpleToMap(GetStickPosts(h), func(v models.Posts) uint64 {
}), true return v.Id
}) })
} }
func (h *Handle) IsStick(id uint64) bool { func (h *Handle) IsStick(id uint64) bool {
return maps.IsExists(h.StickMapPosts(), id) _, ok := GetStickMapPosts(h)[id]
return ok
} }

View File

@ -10,6 +10,7 @@ import (
"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"
str "github.com/fthvgb1/wp-go/helper/strings" str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/safety"
"github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"html/template" "html/template"
@ -19,30 +20,26 @@ import (
) )
type Handle struct { type Handle struct {
Index *IndexHandle C *gin.Context
Detail *DetailHandle theme string
C *gin.Context isInited bool
theme string Session sessions.Session
Session sessions.Session ginH gin.H
ginH gin.H password string
password string scene string
scene string Code int
Code int Stats string
Stats string templ string
templ string themeMods wpconfig.ThemeMods
components map[string]map[string][]Components[string] err error
componentHook map[string][]func(Components[string]) (Components[string], bool) abort bool
themeMods wpconfig.ThemeMods stopPipe bool
handlers map[string]map[string][]HandleCall template *template.Template
handleHook map[string][]func(HandleCall) (HandleCall, bool)
err error
abort bool
stopPipe bool
componentsArgs map[string]any
componentFilterFn map[string][]func(*Handle, string, ...any) string
template *template.Template
} }
var handlerss = safety.NewMap[string, map[string][]HandleCall]()
var handleHooks = safety.NewMap[string, []func(HandleCall) (HandleCall, bool)]()
func (h *Handle) Theme() string { func (h *Handle) Theme() string {
return h.theme return h.theme
} }
@ -55,20 +52,20 @@ func (h *Handle) SetScene(scene string) {
h.scene = scene h.scene = scene
} }
func (h *Handle) Components() map[string]map[string][]Components[string] { func (h *Handle) Components() *safety.Map[string, map[string][]Components[string]] {
return h.components return handleComponents
} }
func (h *Handle) ComponentHook() map[string][]func(Components[string]) (Components[string], bool) { func (h *Handle) ComponentHook() *safety.Map[string, []func(Components[string]) (Components[string], bool)] {
return h.componentHook return handleComponentHook
} }
func (h *Handle) Handlers() map[string]map[string][]HandleCall { func (h *Handle) Handlers() *safety.Map[string, map[string][]HandleCall] {
return h.handlers return handlerss
} }
func (h *Handle) HandleHook() map[string][]func(HandleCall) (HandleCall, bool) { func (h *Handle) HandleHook() *safety.Map[string, []func(HandleCall) (HandleCall, bool)] {
return h.handleHook return handleHooks
} }
func (h *Handle) SetTemplate(template *template.Template) { func (h *Handle) SetTemplate(template *template.Template) {
@ -98,45 +95,48 @@ type HandleCall struct {
Name string Name string
} }
func InitHandle(fn func(*Handle), h *Handle) { func SetConfigHandle(a ...any) Handle {
var inited = false configFn := a[0].(func(*Handle))
hh := reload.GetAnyValBys("themeArgAndConfig", h, func(h *Handle) (Handle, bool) { hh := a[1].(*Handle)
h.components = make(map[string]map[string][]Components[string]) h := &Handle{}
h.componentsArgs = make(map[string]any) mut := reload.GetGlobeMutex()
h.componentFilterFn = make(map[string][]func(*Handle, string, ...any) string) mut.Lock()
h.handlers = make(map[string]map[string][]HandleCall) defer mut.Unlock()
h.handleHook = make(map[string][]func(HandleCall) (HandleCall, bool)) handleComponents.Flush()
h.ginH = gin.H{} componentsArgs.Flush()
fnMap.Flush() handleComponentHook.Flush()
fnHook.Flush() componentFilterFns.Flush()
fn(h) handlerss.Flush()
v := apply.UsePlugins() handleHooks.Flush()
pluginFn, ok := v.(func(*Handle)) h.ginH = gin.H{}
if ok { fnMap.Flush()
pluginFn(h) fnHook.Flush()
} h.C = hh.C
h.C.Set("inited", true) h.theme = hh.theme
inited = true h.template = hh.template
return *h, true configFn(h)
}) v := apply.UsePlugins()
pluginFn, ok := v.(func(*Handle))
if ok {
pluginFn(h)
}
return *h
}
var GetInitHandleFn = reload.BuildValFnWithAnyParams("themeArgAndConfig", SetConfigHandle, 100.01)
type ConfigParm struct {
ConfigFn func(*Handle)
H *Handle
}
func InitHandle(configFn func(*Handle), h *Handle) {
hh := GetInitHandleFn(configFn, h)
h.ginH = maps.Copy(hh.ginH) h.ginH = maps.Copy(hh.ginH)
h.ginH["calPostClass"] = postClass(h) h.ginH["calPostClass"] = postClass(h)
h.ginH["calBodyClass"] = bodyClass(h) h.ginH["calBodyClass"] = bodyClass(h)
h.ginH["customLogo"] = customLogo(h) h.ginH["customLogo"] = customLogo(h)
if inited { h.isInited = true
return
}
h.components = hh.components
h.Index.postsPlugin = hh.Index.postsPlugin
h.Index.pageEle = hh.Index.pageEle
h.Detail.CommentRender = hh.Detail.CommentRender
h.Detail.CommentPageEle = hh.Detail.CommentPageEle
h.handlers = hh.handlers
h.handleHook = hh.handleHook
h.componentHook = hh.componentHook
h.componentsArgs = hh.componentsArgs
h.componentFilterFn = hh.componentFilterFn
h.C.Set("inited", true)
} }
func (h *Handle) Abort() { func (h *Handle) Abort() {

View File

@ -181,10 +181,10 @@ func NewPaginationCache[K comparable, V any](m *cache.MapCache[string, helper.Pa
} }
} }
if ma == nil { if ma == nil {
ma = reload.FnVal(str.Join("paginationCache-", name, "-maxNum"), maxNum, nil) ma = reload.BuildFnVal(str.Join("paginationCache-", name, "-maxNum"), maxNum, nil)
} }
if fet == nil { if fet == nil {
fet = reload.FnVal(str.Join("paginationCache-", name, "-fetchNum"), fetchNum, nil) fet = reload.BuildFnVal(str.Join("paginationCache-", name, "-fetchNum"), fetchNum, nil)
} }
p := cache.NewPagination(m, ma, dbFn, localFn, dbKeyFn, localKeyFn, fet, name) p := cache.NewPagination(m, ma, dbFn, localFn, dbKeyFn, localKeyFn, fet, name)
mapCache.Store(name, p) mapCache.Store(name, p)
@ -215,7 +215,7 @@ func buildLockFn[K comparable](args ...any) cache.LockFn[K] {
} }
loFn = helper.ParseArgs(loFn, args...) loFn = helper.ParseArgs(loFn, args...)
if name != "" { if name != "" {
loFn = reload.FnVal(str.Join("cachesLocksNum-", name), num, loFn) loFn = reload.BuildFnVal(str.Join("cachesLocksNum-", name), num, loFn)
} }
if lockFn == nil { if lockFn == nil {
looo := helper.ParseArgs(cache.Lockss[K](nil), args...) looo := helper.ParseArgs(cache.Lockss[K](nil), args...)
@ -247,13 +247,13 @@ func SetExpireTime(c cache.SetTime, name string, expireTime time.Duration, expir
if name == "" { if name == "" {
return return
} }
fn := reload.FnVal(str.Join("cacheManger-", name, "-expiredTime"), expireTime, expireTimeFn) fn := reload.BuildFnVal(str.Join("cacheManger-", name, "-expiredTime"), expireTime, expireTimeFn)
c.SetExpiredTime(fn) c.SetExpiredTime(fn)
} }
func ChangeExpireTime(t time.Duration, coverConf bool, name ...string) { func ChangeExpireTime(t time.Duration, coverConf bool, name ...string) {
for _, s := range name { for _, s := range name {
reload.ChangeFnVal(s, t, coverConf) reload.SetFnVal(s, t, coverConf)
} }
} }

2
cache/map.go vendored
View File

@ -56,7 +56,7 @@ type IncreaseUpdate[K comparable, V any] struct {
} }
func NewIncreaseUpdate[K comparable, V any](name string, fn IncreaseFn[K, V], cycleTime time.Duration, tFn func() time.Duration) *IncreaseUpdate[K, V] { func NewIncreaseUpdate[K comparable, V any](name string, fn IncreaseFn[K, V], cycleTime time.Duration, tFn func() time.Duration) *IncreaseUpdate[K, V] {
tFn = reload.FnVal(name, cycleTime, tFn) tFn = reload.BuildFnVal(name, cycleTime, tFn)
return &IncreaseUpdate[K, V]{CycleTime: tFn, Fn: fn} return &IncreaseUpdate[K, V]{CycleTime: tFn, Fn: fn}
} }

4
cache/map_test.go vendored
View File

@ -23,7 +23,7 @@ func init() {
ct = context.Background() ct = context.Background()
batchFn = func(ctx context.Context, arr []string, a ...any) (map[string]string, error) { batchFn = func(ctx context.Context, arr []string, a ...any) (map[string]string, error) {
fmt.Println(a) fmt.Println(a)
return slice.FilterAndToMap(arr, func(t string) (string, string, bool) { return slice.FilterAndToMap(arr, func(t string, _ int) (string, string, bool) {
return t, strings.Repeat(t, 2), true return t, strings.Repeat(t, 2), true
}), nil }), nil
} }
@ -69,7 +69,7 @@ func TestMapCache_Flush(t *testing.T) {
} }
ca := *NewMapCache[string, string](NewMemoryMapCache[string, string](func() time.Duration { ca := *NewMapCache[string, string](NewMemoryMapCache[string, string](func() time.Duration {
return time.Second return time.Second
}), fn, nil) }), fn, nil, nil, nil)
_, _ = ca.GetCache(ct, "aa", time.Second, ct, "aa") _, _ = ca.GetCache(ct, "aa", time.Second, ct, "aa")
tests := []testCase[string, string]{ tests := []testCase[string, string]{
{ {

373
cache/reload/reload.go vendored
View File

@ -14,32 +14,47 @@ type queue struct {
name string name string
} }
var calls = safety.NewSlice(make([]queue, 0)) var mut = &sync.Mutex{}
var callsM = safety.NewMap[string, func()]()
var anyMap = safety.NewMap[string, any]() func GetGlobeMutex() *sync.Mutex {
return mut
}
type safetyVar[T, A any] struct { var waitReloadCalls = safety.NewSlice(make([]queue, 0))
Val *safety.Var[val[T]] var callMap = safety.NewMap[string, func()]()
mutex sync.Mutex
var setFnVal = safety.NewMap[string, any]()
type SafetyVar[T, A any] struct {
Val *safety.Var[Val[T]]
Mutex sync.Mutex
} }
type val[T any] struct { type Val[T any] struct {
v T V T
ok bool Ok bool
counter number.Counter[int]
} }
type safetyMap[K comparable, V, A any] struct { type SafetyMap[K comparable, V, A any] struct {
val *safety.Map[K, V] Val *safety.Map[K, V]
mutex sync.Mutex Mutex sync.Mutex
} }
var safetyMaps = safety.NewMap[string, any]() var safetyMaps = safety.NewMap[string, any]()
var safetyMapLock = sync.Mutex{} var safetyMapLock = sync.Mutex{}
var flushMapFn = safety.NewMap[string, func(any)]() var deleteMapFn = safety.NewMap[string, func(any)]()
func FlushMapVal[T any](namespace string, key ...T) { // GetValMap can get stored map value with namespace which called BuildSafetyMap, BuildMapFnWithConfirm, BuildMapFn, BuildMapFnWithAnyParams
fn, ok := flushMapFn.Load(namespace) func GetValMap[K comparable, V any](namespace string) (*safety.Map[K, V], bool) {
m, ok := safetyMaps.Load(namespace)
if !ok {
return nil, false
}
v, ok := m.(*safety.Map[K, V])
return v, ok
}
func DeleteMapVal[T any](namespace string, key ...T) {
fn, ok := deleteMapFn.Load(namespace)
if !ok || len(key) < 1 { if !ok || len(key) < 1 {
return return
} }
@ -48,7 +63,7 @@ func FlushMapVal[T any](namespace string, key ...T) {
func FlushAnyVal(namespaces ...string) { func FlushAnyVal(namespaces ...string) {
for _, namespace := range namespaces { for _, namespace := range namespaces {
fn, ok := callsM.Load(namespace) fn, ok := callMap.Load(namespace)
if !ok { if !ok {
continue continue
} }
@ -56,93 +71,142 @@ func FlushAnyVal(namespaces ...string) {
} }
} }
func GetAnyMapFnBys[K comparable, V, A any](namespace string, fn func(A) V) func(key K, args A) V { // BuildMapFnWithConfirm same as BuildMapFn
m := safetyMapFn[K, V, A](namespace) func BuildMapFnWithConfirm[K comparable, V, A any](namespace string, fn func(A) (V, bool), a ...any) func(key K, args A) V {
m := BuildSafetyMap[K, V, A](namespace, a...)
return func(key K, a A) V { return func(key K, a A) V {
v, ok := m.val.Load(key) v, ok := m.Val.Load(key)
if ok { if ok {
return v return v
} }
m.mutex.Lock() m.Mutex.Lock()
defer m.mutex.Unlock() defer m.Mutex.Unlock()
v, ok = m.val.Load(key) v, ok = m.Val.Load(key)
if ok {
return v
}
v, ok = fn(a)
if ok {
m.Val.Store(key, v)
}
return v
}
}
// BuildMapFn build given fn with a new fn which returned value can be saved and flushed when called Reload or FlushAnyVal
// with namespace
//
// if give a float then can be reloaded early or lately, more bigger more earlier
//
// if give a bool false will not flushed when called Reload, then can called GetValMap to flush manually
func BuildMapFn[K comparable, V, A any](namespace string, fn func(A) V, a ...any) func(key K, args A) V {
m := BuildSafetyMap[K, V, A](namespace, a...)
return func(key K, a A) V {
v, ok := m.Val.Load(key)
if ok {
return v
}
m.Mutex.Lock()
defer m.Mutex.Unlock()
v, ok = m.Val.Load(key)
if ok { if ok {
return v return v
} }
v = fn(a) v = fn(a)
m.val.Store(key, v) m.Val.Store(key, v)
return v return v
} }
} }
func safetyMapFn[K comparable, V, A any](namespace string, args ...any) *safetyMap[K, V, A] { // BuildMapFnWithAnyParams same as BuildMapFn use multiple params
vv, ok := safetyMaps.Load(namespace) func BuildMapFnWithAnyParams[K comparable, V any](namespace string, fn func(...any) V, a ...any) func(key K, a ...any) V {
var m *safetyMap[K, V, A] m := BuildSafetyMap[K, V, any](namespace, a...)
if ok { return func(key K, a ...any) V {
m = vv.(*safetyMap[K, V, A]) v, ok := m.Val.Load(key)
} else {
safetyMapLock.Lock()
defer safetyMapLock.Unlock()
vv, ok = safetyMaps.Load(namespace)
if ok { if ok {
m = vv.(*safetyMap[K, V, A]) return v
} else {
m = &safetyMap[K, V, A]{safety.NewMap[K, V](), sync.Mutex{}}
ord, _ := parseArgs(args...)
flushMapFn.Store(namespace, func(a any) {
k, ok := a.([]K)
if !ok && len(k) > 0 {
return
}
for _, key := range k {
m.val.Delete(key)
}
})
Push(func() {
m.val.Flush()
}, ord, namespace)
safetyMaps.Store(namespace, m)
} }
m.Mutex.Lock()
defer m.Mutex.Unlock()
v, ok = m.Val.Load(key)
if ok {
return v
}
v = fn(a)
m.Val.Store(key, v)
return v
} }
}
func BuildSafetyMap[K comparable, V, A any](namespace string, args ...any) *SafetyMap[K, V, A] {
vv, ok := safetyMaps.Load(namespace)
var m *SafetyMap[K, V, A]
if ok {
m = vv.(*SafetyMap[K, V, A])
return m
}
safetyMapLock.Lock()
defer safetyMapLock.Unlock()
vv, ok = safetyMaps.Load(namespace)
if ok {
m = vv.(*SafetyMap[K, V, A])
return m
}
m = &SafetyMap[K, V, A]{safety.NewMap[K, V](), sync.Mutex{}}
ord, _ := parseArgs(args...)
autoFlush := helper.ParseArgs(true, args...)
deleteMapFn.Store(namespace, func(a any) {
k, ok := a.([]K)
if !ok && len(k) > 0 {
return
}
for _, key := range k {
m.Val.Delete(key)
}
})
if autoFlush {
Push(func() {
m.Val.Flush()
}, ord, namespace)
}
safetyMaps.Store(namespace, m)
return m return m
} }
func GetAnyValMapBy[K comparable, V, A any](namespace string, key K, a A, fn func(A) (V, bool), args ...any) V { func GetAnyValMapBy[K comparable, V, A any](namespace string, key K, a A, fn func(A) (V, bool), args ...any) V {
m := safetyMapFn[K, V, A](namespace, args...) m := BuildSafetyMap[K, V, A](namespace, args...)
v, ok := m.val.Load(key) v, ok := m.Val.Load(key)
if ok { if ok {
return v return v
} }
m.mutex.Lock() m.Mutex.Lock()
defer m.mutex.Unlock() defer m.Mutex.Unlock()
v, ok = m.val.Load(key) v, ok = m.Val.Load(key)
if ok { if ok {
return v return v
} }
v, ok = fn(a) v, ok = fn(a)
if ok { if ok {
m.val.Store(key, v) m.Val.Store(key, v)
} }
return v return v
} }
func anyVal[T, A any](namespace string, counter bool, args ...any) *safetyVar[T, A] { func BuildAnyVal[T, A any](namespace string, counter bool, args ...any) *SafetyVar[T, A] {
var vv *safetyVar[T, A] var vv *SafetyVar[T, A]
vvv, ok := safetyMaps.Load(namespace) vvv, ok := safetyMaps.Load(namespace)
if ok { if ok {
vv = vvv.(*safetyVar[T, A]) vv = vvv.(*SafetyVar[T, A])
} else { } else {
safetyMapLock.Lock() safetyMapLock.Lock()
defer safetyMapLock.Unlock() defer safetyMapLock.Unlock()
vvv, ok = safetyMaps.Load(namespace) vvv, ok = safetyMaps.Load(namespace)
if ok { if ok {
vv = vvv.(*safetyVar[T, A]) vv = vvv.(*SafetyVar[T, A])
} else { } else {
v := val[T]{} v := Val[T]{}
if counter { vv = &SafetyVar[T, A]{safety.NewVar(v), sync.Mutex{}}
v.counter = number.Counters[int]()
}
vv = &safetyVar[T, A]{safety.NewVar(v), sync.Mutex{}}
ord, _ := parseArgs(args...) ord, _ := parseArgs(args...)
Push(func() { Push(func() {
vv.Val.Flush() vv.Val.Flush()
@ -153,53 +217,117 @@ func anyVal[T, A any](namespace string, counter bool, args ...any) *safetyVar[T,
return vv return vv
} }
func GetAnyValBy[T, A any](namespace string, a A, fn func(A) (T, bool), args ...any) T { func GetAnyValBys[T, A any](namespace string, a A, fn func(A) (T, bool), args ...any) T {
var vv = anyVal[T, A](namespace, true, args...) var vv = BuildAnyVal[T, A](namespace, false, args...)
var ok bool
v := vv.Val.Load() v := vv.Val.Load()
if v.ok { if v.Ok {
return v.v return v.V
} }
vv.mutex.Lock() vv.Mutex.Lock()
defer vv.mutex.Unlock() defer vv.Mutex.Unlock()
v = vv.Val.Load() v = vv.Val.Load()
if v.ok { if v.Ok {
return v.v return v.V
} }
v.v, ok = fn(a) v.V, v.Ok = fn(a)
if v.counter == nil { vv.Val.Store(v)
v.counter = number.Counters[int]() return v.V
}
times := v.counter()
tryTimes := helper.ParseArgs(1, args...)
if ok || times >= tryTimes {
v.ok = true
vv.Val.Store(v)
}
return v.v
} }
func GetAnyValBys[T, A any](namespace string, a A, fn func(A) (T, bool), args ...any) T { // BuildValFnWithConfirm same as BuildValFn
var vv = anyVal[T, A](namespace, false, args...) //
v := vv.Val.Load() // if give a int and value bigger than 1 will be a times which built fn called return false
if v.ok { func BuildValFnWithConfirm[T, A any](namespace string, fn func(A) (T, bool), args ...any) func(A) T {
return v.v var vv = BuildAnyVal[T, A](namespace, false, args...)
tryTimes := helper.ParseArgs(1, args...)
var counter func() int
if tryTimes > 1 {
counter = number.Counters[int]()
} }
vv.mutex.Lock() return func(a A) T {
defer vv.mutex.Unlock() v := vv.Val.Load()
v = vv.Val.Load() if v.Ok {
if v.ok { return v.V
return v.v }
vv.Mutex.Lock()
defer vv.Mutex.Unlock()
v = vv.Val.Load()
if v.Ok {
return v.V
}
v.V, v.Ok = fn(a)
if v.Ok {
vv.Val.Store(v)
return v.V
}
if counter == nil {
return v.V
}
times := counter()
if times >= tryTimes {
v.Ok = true
vv.Val.Store(v)
}
return v.V
}
}
// BuildValFn build given fn a new fn which return value can be saved and flushed when called Reload or FlushAnyVal
// with namespace.
//
// note: namespace should be not same as BuildMapFn and related fn, they stored same safety.Map[string,any].
//
// if give a float then can be reloaded early or lately, more bigger more earlier
//
// if give a bool false will not flushed when called Reload, then can called GetValMap to flush manually
func BuildValFn[T, A any](namespace string, fn func(A) T, args ...any) func(A) T {
var vv = BuildAnyVal[T, A](namespace, false, args...)
return func(a A) T {
v := vv.Val.Load()
if v.Ok {
return v.V
}
vv.Mutex.Lock()
defer vv.Mutex.Unlock()
v = vv.Val.Load()
if v.Ok {
return v.V
}
v.V = fn(a)
v.Ok = true
vv.Val.Store(v)
return v.V
}
}
// BuildValFnWithAnyParams same as BuildValFn use multiple params
func BuildValFnWithAnyParams[T any](namespace string, fn func(...any) T, args ...any) func(...any) T {
var vv = BuildAnyVal[T, any](namespace, false, args...)
return func(a ...any) T {
v := vv.Val.Load()
if v.Ok {
return v.V
}
vv.Mutex.Lock()
defer vv.Mutex.Unlock()
v = vv.Val.Load()
if v.Ok {
return v.V
}
v.V = fn(a...)
v.Ok = true
vv.Val.Store(v)
return v.V
} }
v.v, v.ok = fn(a)
vv.Val.Store(v)
return v.v
} }
// Vars get default value and whenever reloaded assign default value // Vars get default value and whenever reloaded assign default value
// //
// args same as Push // args same as Push
//
// if give a name, then can be flushed by calls FlushAnyVal // if give a name, then can be flushed by calls FlushAnyVal
//
// if give a float then can be reloaded early or lately, more bigger more earlier
func Vars[T any](defaults T, args ...any) *safety.Var[T] { func Vars[T any](defaults T, args ...any) *safety.Var[T] {
ss := safety.NewVar(defaults) ss := safety.NewVar(defaults)
ord, name := parseArgs(args...) ord, name := parseArgs(args...)
@ -261,37 +389,42 @@ func SafeMap[K comparable, T any](args ...any) *safety.Map[K, T] {
return m return m
} }
// Push the func that will be call whenever Reload called // Push the func that will be called whenever Reload called
// //
// if give a name, then can be flushed by calls FlushAnyVal // if give a name, then can be called by called FlushAnyVal
//
// if give a float then can be called early or lately when called Reload, more bigger more earlier
func Push(fn func(), a ...any) { func Push(fn func(), a ...any) {
ord, name := parseArgs(a...) ord, name := parseArgs(a...)
calls.Append(queue{fn, ord, name}) waitReloadCalls.Append(queue{fn, ord, name})
if name != "" { if name != "" {
callsM.Store(name, fn) callMap.Store(name, fn)
} }
} }
func Reload() { func Reload() {
callsM.Flush() mut.Lock()
flushMapFn.Flush() defer mut.Unlock()
callll := calls.Load() callMap.Flush()
slice.SimpleSort(callll, slice.DESC, func(t queue) float64 { deleteMapFn.Flush()
reloadCalls := waitReloadCalls.Load()
slice.SimpleSort(reloadCalls, slice.DESC, func(t queue) float64 {
return t.order return t.order
}) })
for _, call := range callll { for _, call := range reloadCalls {
call.fn() call.fn()
} }
return return
} }
type Any[T any] struct { type Any[T any] struct {
fn func() T fn func() T
v *safety.Var[T] v *safety.Var[T]
isUseManger *safety.Var[bool] isManual *safety.Var[bool]
} }
func FnVal[T any](name string, t T, fn func() T) func() T { // BuildFnVal build a new fn which can be set value by SetFnVal with name or set default value by given fn when called Reload
func BuildFnVal[T any](name string, t T, fn func() T) func() T {
if fn == nil { if fn == nil {
fn = func() T { fn = func() T {
return t return t
@ -301,23 +434,23 @@ func FnVal[T any](name string, t T, fn func() T) func() T {
} }
p := safety.NewVar(t) p := safety.NewVar(t)
e := Any[T]{ e := Any[T]{
fn: fn, fn: fn,
v: p, v: p,
isUseManger: safety.NewVar(false), isManual: safety.NewVar(false),
} }
Push(func() { Push(func() {
if !e.isUseManger.Load() { if !e.isManual.Load() {
e.v.Store(fn()) e.v.Store(fn())
} }
}) })
anyMap.Store(name, e) setFnVal.Store(name, e)
return func() T { return func() T {
return e.v.Load() return e.v.Load()
} }
} }
func ChangeFnVal[T any](name string, val T, coverConf bool) { func SetFnVal[T any](name string, val T, onlyManual bool) {
v, ok := anyMap.Load(name) v, ok := setFnVal.Load(name)
if !ok { if !ok {
return return
} }
@ -325,8 +458,8 @@ func ChangeFnVal[T any](name string, val T, coverConf bool) {
if !ok { if !ok {
return return
} }
if coverConf && !vv.isUseManger.Load() { if onlyManual && !vv.isManual.Load() {
vv.isUseManger.Store(true) vv.isManual.Store(true)
} }
vv.v.Store(val) vv.v.Store(val)
} }

View File

@ -13,7 +13,7 @@ func TestFlushMapVal(t *testing.T) {
return 33, true return 33, true
}) })
fmt.Println(v) fmt.Println(v)
FlushMapVal("key", 2) DeleteMapVal("key", 2)
v = GetAnyValMapBy("key", 2, struct{}{}, func(a struct{}) (int, bool) { v = GetAnyValMapBy("key", 2, struct{}{}, func(a struct{}) (int, bool) {
fmt.Println("xxxxx") fmt.Println("xxxxx")
@ -32,15 +32,15 @@ func TestFlushMapVal(t *testing.T) {
func TestGetAnyMapFnBys(t *testing.T) { func TestGetAnyMapFnBys(t *testing.T) {
var i int var i int
t.Run("t1", func(t *testing.T) { t.Run("t1", func(t *testing.T) {
v := GetAnyMapFnBys[int]("name", func(a int) int { v := BuildMapFnWithConfirm[int]("name", func(a int) (int, bool) {
i++ i++
return a + 1 return a + 1, true
}) })
vv := v(1, 2) vv := v(1, 2)
vvv := v(2, 3) vvv := v(2, 3)
fmt.Println(vv, vvv) fmt.Println(vv, vvv)
v(1, 2) v(1, 2)
FlushMapVal("name", 2) DeleteMapVal("name", 2)
v(2, 3) v(2, 3)
fmt.Println(i) fmt.Println(i)
}) })

View File

@ -192,8 +192,8 @@ func WithDefaultVal[K comparable, V any](m map[K]V, k K, defaults V) V {
return defaults return defaults
} }
func AnyAnyMap[K comparable, V any](m map[any]any, fn func(k, v any) (K, V, bool)) map[K]V { func AnyAnyMapTo[K comparable, V any](m map[any]any, fn func(k, v any) (K, V, bool)) map[K]V {
mm := make(map[K]V, 0) mm := make(map[K]V)
for k, v := range m { for k, v := range m {
key, val, ok := fn(k, v) key, val, ok := fn(k, v)
if ok { if ok {

View File

@ -172,10 +172,10 @@ func Slice[T any](arr []T, offset, length int) (r []T) {
return return
} }
func FilterAndToMap[K comparable, V, T any](arr []T, fn func(T) (K, V, bool)) map[K]V { func FilterAndToMap[K comparable, V, T any](arr []T, fn func(T, int) (K, V, bool)) map[K]V {
r := make(map[K]V) r := make(map[K]V)
for _, t := range arr { for i, t := range arr {
k, v, ok := fn(t) k, v, ok := fn(t, i)
if ok { if ok {
r[k] = v r[k] = v
} }