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) {
t := theme.GetCurrentTemplateName()
h := wp.NewHandle(c, scene, t)
h.Index = wp.NewIndexHandle(h)
h.Detail = wp.NewDetailHandle(h)
templ, _ := theme.GetTemplate(t)
h.SetTemplate(templ)
theme.Hook(t, h)

View File

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

View File

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

View File

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

View File

@ -23,7 +23,7 @@ func configs(h *wp.Handle) {
})
wp.InitPipe(h)
middleware.CommonMiddleware(h)
h.Index.SetPageEle(plugins.TwentyFifteenPagination())
setPaginationAndRender(h)
h.PushCacheGroupHeadScript(constraints.AllScene, "CalCustomBackGround", 10.005, CalCustomBackGround)
h.PushCacheGroupHeadScript(constraints.AllScene, "colorSchemeCss", 10.0056, colorSchemeCss)
h.CommonComponents()
@ -39,8 +39,22 @@ func configs(h *wp.Handle) {
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) {
if h.Detail.Post.Thumbnail.Path != "" {
h.Detail.Post.Thumbnail = wpconfig.Thumbnail(h.Detail.Post.Thumbnail.OriginAttachmentData, "post-thumbnail", "")
d := h.GetDetailHandle()
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)
pushScripts(h)
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">`,
"{$after_widget}": `</section>`,
})
@ -67,13 +67,11 @@ func configs(h *wp.Handle) {
)
videoHeader(h)
h.SetData("colophon", colophon)
h.Detail.CommentRender = commentFormat
h.Detail.CommentPageEle = commentPageEle
setPaginationAndRender(h)
h.CommonComponents()
h.Index.SetPageEle(paginate)
wp.ReplyCommentJs(h)
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"))
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"))
@ -81,6 +79,18 @@ func configs(h *wp.Handle) {
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="/">
<label for="search-form-1">
<span class="screen-reader-text">{$label}</span>
@ -101,7 +111,7 @@ func errorsHandle(h *wp.Handle) {
}
func postThumb(h *wp.Handle) {
d := h.Detail
d := h.GetDetailHandle()
if d.Post.Thumbnail.Path != "" {
img := wpconfig.Thumbnail(d.Post.Thumbnail.OriginAttachmentData, "full", "", "thumbnail", "post-thumbnail")
img.Sizes = "100vw"

View File

@ -33,14 +33,14 @@ func (h *Handle) BodyClass() string {
case constraints.Search:
s := "search-no-results"
if len(h.Index.Posts) > 0 {
if len(h.GetIndexHandle().Posts) > 0 {
s = "search-results"
}
class = append(class, "search", s)
case constraints.Category, constraints.Tag:
class = append(class, "archive", "category")
cat := h.Index.Param.Category
cat := h.GetIndexHandle().Param.Category
if cat == "" {
break
}
@ -54,7 +54,7 @@ func (h *Handle) BodyClass() string {
case constraints.Author:
class = append(class, "archive", "author")
author := h.Index.Param.Author
author := h.GetIndexHandle().Param.Author
user, _ := cache.GetUserByName(h.C, author)
class = append(class, str.Join("author-", number.IntToString(user.Id)))
if user.DisplayName[0] != '%' {
@ -63,7 +63,7 @@ func (h *Handle) BodyClass() string {
case constraints.Detail:
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 {
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/slice"
str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/safety"
"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) {
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
})
handleComponentHook.Store(scene, v)
}
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 {
c = components
}
return c, true
})
handleComponentHook.Store(scene, v)
}
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) {
componentss := reload.GetAnyValMapBy("scene-components", str.Join("allScene-", h.scene), h, func(h *Handle) (map[string][]Components[string], bool) {
return maps.MergeBy(func(k string, v1, v2 []Components[string]) ([]Components[string], bool) {
vv := append(v1, v2...)
return vv, vv != nil
}, nil, h.components[h.scene], h.components[constraints.AllScene]), true
})
for k, components := range componentss {
allComponents := getComponentFn(str.Join("allScene-", h.scene), h)
for k, components := range allComponents {
key := str.Join("calComponents-", h.scene, "-", k)
ss := reload.GetAnyValMapBy("calComponents", key, h, func(h *Handle) ([]Components[string], bool) {
r := slice.FilterAndMap(components, func(t Components[string]) (Components[string], bool) {
fns, ok := h.componentHook[k]
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 {
hookedComponents := hookComponentFn(key, componentParam{components, k})
var s = make([]string, 0, len(hookedComponents))
for _, component := range hookedComponents {
if component.Val != "" {
s = append(s, component.Val)
continue
@ -64,9 +113,7 @@ func CalComponents(h *Handle) {
if component.Fn != nil {
v := ""
if component.Cached {
v = reload.GetAnyValMapBy("cacheComponents", component.Name, h, func(a *Handle) (string, bool) {
return component.Fn(h), true
})
v = cacheComponentsFn(component.Name, cacheComponentParm[string]{component, h})
} else {
v = component.Fn(h)
}
@ -80,12 +127,12 @@ func CalComponents(h *Handle) {
}
func (h *Handle) PushComponents(scene, componentType string, components ...Components[string]) {
c, ok := h.components[scene]
c, ok := handleComponents.Load(scene)
if !ok {
c = make(map[string][]Components[string])
h.components[scene] = c
}
c[componentType] = append(c[componentType], components...)
handleComponents.Store(scene, c)
}
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...)
}
func GetComponentsArgs[T any](h *Handle, k string, defaults T) T {
v, ok := h.componentsArgs[k]
func GetComponentsArgs[T any](k string, defaults T) T {
v, ok := componentsArgs.Load(k)
if ok {
vv, ok := v.(T)
if ok {
@ -152,60 +199,61 @@ func GetComponentsArgs[T any](h *Handle, k string, defaults T) T {
return defaults
}
func PushComponentsArgsForSlice[T any](h *Handle, name string, v ...T) {
val, ok := h.componentsArgs[name]
func PushComponentsArgsForSlice[T any](name string, v ...T) {
val, ok := componentsArgs.Load(name)
if !ok {
var vv []T
vv = append(vv, v...)
h.componentsArgs[name] = vv
componentsArgs.Store(name, vv)
return
}
vv, ok := val.([]T)
if ok {
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) {
val, ok := h.componentsArgs[name]
func SetComponentsArgsForMap[K comparable, V any](name string, key K, v V) {
val, ok := componentsArgs.Load(name)
if !ok {
vv := make(map[K]V)
vv[key] = v
h.componentsArgs[name] = vv
componentsArgs.Store(name, vv)
return
}
vv, ok := val.(map[K]V)
if ok {
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) {
val, ok := h.componentsArgs[name]
func MergeComponentsArgsForMap[K comparable, V any](name string, m map[K]V) {
val, ok := componentsArgs.Load(name)
if !ok {
h.componentsArgs[name] = m
componentsArgs.Store(name, m)
return
}
vv, ok := val.(map[K]V)
if ok {
h.componentsArgs[name] = maps.Merge(vv, m)
componentsArgs.Store(name, maps.Merge(vv, m))
}
}
func SetComponentsArgs(h *Handle, key string, value any) {
h.componentsArgs[key] = value
func SetComponentsArgs(key string, value any) {
componentsArgs.Store(key, value)
}
func (h *Handle) ComponentFilterFn(name string) ([]func(*Handle, string, ...any) string, bool) {
fn, ok := h.componentFilterFn[name]
return fn, ok
func (h *Handle) GetComponentFilterFn(name string) ([]func(*Handle, string, ...any) string, bool) {
return componentFilterFns.Load(name)
}
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 {
calls, ok := h.componentFilterFn[name]
calls, ok := componentFilterFns.Load(name)
if ok {
return slice.Reduce(calls, func(fn func(*Handle, string, ...any) string, r string) string {
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
class := maps.GetAnyAnyValWithDefaults(attr, "", "className")
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")
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)
if !ok {
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(`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) {
counter := number.Counters[int]()
var err error
conf := reload.GetAnyValBy("block-category-conf", h, func(h *wp.Handle) (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
}, 5)
conf := GetCategoryConf(blockParser)
if err != nil {
return nil, err
@ -127,10 +140,7 @@ func Category(h *wp.Handle, id string, blockParser ParserBlock) (func() string,
if maps.GetAnyAnyValWithDefaults(conf, false, "showOnlyTopLevel") {
h.C.Set("showOnlyTopLevel", true)
}
args := reload.GetAnyValBys("block-category-args", h, func(h *wp.Handle) (map[string]string, bool) {
args := wp.GetComponentsArgs(h, widgets.Widget, map[string]string{})
return maps.FilterZeroMerge(categoryDefaultArgs(), args), true
})
args := GetCategoryArgs()
return func() string {
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}"])
}
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()
li := widget.CategoryLi(h, conf, categories)
attrs := reload.GetAnyValBys("block-category-attr", conf, parseAttr)
li := widget.CategoryLi(h, confAttr, categories)
attrs := GetCategoryAttr(confAttr)
s.Sprintf(`<ul %s>%s</ul>`, attrs, li)
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()
ids := fmt.Sprintf(`wp-block-categories-%v`, id)
args = maps.Copy(args)
args["{$selectId}"] = ids
attrs := reload.GetAnyValBys("block-category-attr", conf, parseAttr)
selects := widget.DropdownCategories(h, args, conf, categories)
attrs := GetCategoryAttr(confAttr)
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))
return s.String()
}

View File

@ -40,21 +40,29 @@ var archivesConfig = map[any]any{
"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 {
conf := configs(archivesConfig, "widget_archives", int64(2))
args := reload.GetAnyValBys("widget-archive-args", h, func(h *wp.Handle) (map[string]string, bool) {
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
})
conf := GetArchiveConf()
args := GetArchiveArgs(h, conf, id)
s := archiveTemplate
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 {
option := str.NewBuilder()
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)
for _, archive := range archives {
sel := ""
if h.Index.Param.Year == archive.Year && month == archive.Month {
if i.Param.Year == archive.Year && month == archive.Month {
sel = "selected"
}
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 {
conf := configs(categoryConfig, "widget_categories", int64(2))
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
})
conf := GetCategoryConf()
args := GetCategoryArgs(h, conf, id)
t := categoryTemplate
dropdown := conf["dropdown"].(int64)
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>
`, args["{$show_option_none}"])
currentCategory := ""
i := h.GetIndexHandle()
if h.Scene() == constraints.Category {
currentCategory = h.Index.Param.Category
currentCategory = i.Param.Category
}
showCount := conf["count"].(int64)
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) {
cate := wp.GetComponentsArgs[map[string]string](h, widgets.Categories, categoryArgs())
cate := wp.GetComponentsArgs[map[string]string](widgets.Categories, categoryArgs())
name, ok := cate["{$name}"]
if !ok || name == "" {
return
@ -260,7 +268,7 @@ func IsCategory(h *wp.Handle) (category models.TermsMy, r bool) {
}
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}"]
if ok {
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 {
return reload.GetAnyValBys(str.Join("widget-config-", key), key, func(_ string) (M, bool) {
c := wpconfig.GetPHPArrayVal[M](key, nil, a...)
return maps.FilterZeroMerge(maps.Copy(m), c), true
})
func configFns[K comparable, V any](m map[K]V, key string, a ...any) func(_ ...any) map[K]V {
return func(_ ...any) map[K]V {
c := wpconfig.GetPHPArrayVal[map[K]V](key, nil, a...)
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}
{$after_widget}`
func metaArgs() map[string]string {
func defaultMetaArgs() map[string]string {
return map[string]string{
"{$aria_label}": "",
"{$title}": "",
}
}
func Meta(h *wp.Handle, id string) string {
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
})
var GetMetaArgs = reload.BuildValFnWithAnyParams("widget-meta-args", ParseMetaArgs)
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()
if str.ToInteger(wpconfig.GetOption("users_can_register"), 0) > 0 {
ss.Sprintf(`<li><a href="/wp-login.php?action=register">注册</li>`)

View File

@ -39,22 +39,29 @@ var recentCommentsTemplate = `{$before_widget}
{$after_widget}
`
func RecentComments(h *wp.Handle, id string) string {
conf := configs(recentCommentConf, "widget_recent-comments", int64(2))
var GetRecentCommentConf = BuildconfigFn(recentCommentConf, "widget_recent-comments", int64(2))
args := reload.GetAnyValBys("widget-recent-comment-args", h, func(h *wp.Handle) (map[string]string, bool) {
commentsArgs := recentCommentsArgs()
commonArgs := wp.GetComponentsArgs(h, widgets.Widget, map[string]string{})
args := wp.GetComponentsArgs(h, widgets.RecentComments, commentsArgs)
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"))
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
})
var GetRecentCommentArgs = reload.BuildValFnWithAnyParams("widget-recent-comment-args", RecentCommentArgs)
func RecentCommentArgs(a ...any) map[string]string {
h := a[0].(*wp.Handle)
conf := a[1].(map[any]any)
id := a[2].(string)
commentsArgs := recentCommentsArgs()
commonArgs := wp.GetComponentsArgs(widgets.Widget, map[string]string{})
args := wp.GetComponentsArgs(widgets.RecentComments, commentsArgs)
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"))
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 {
return fmt.Sprintf(` <li>

View File

@ -25,7 +25,7 @@ var recentPostsTemplate = `{$before_widget}
{$after_widget}
`
func recentPostsArgs() map[string]string {
func DefaultRecentPostsArgs() map[string]string {
return map[string]string{
"{$before_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{
"number": int64(5),
"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 {
conf := reload.GetAnyValBys("widget-recent-posts-conf", h, func(h *wp.Handle) (map[any]any, bool) {
recent := recentConf()
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
})
conf := GetRecentPostConf()
args := GetRecentPostArgs(h, conf, id)
currentPostId := uint64(0)
if h.Scene() == constraints.Detail {
currentPostId = str.ToInteger(h.C.Param("id"), uint64(0))

View File

@ -47,34 +47,40 @@ func searchArgs() map[string]string {
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 {
args := reload.GetAnyValBys("widget-search-args", h, func(h *wp.Handle) (map[string]string, bool) {
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
})
args := GetSearchArgs(h, id)
s := strings.ReplaceAll(searchTemplate, "{$form}", form)
val := ""
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)
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
}
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) {
var err error
img := reload.GetAnyValBy("headerImages", h.theme, func(theme string) ([]models.PostThumbnail, bool) {
hs, er := h.GetHeaderImages(h.theme)
if er != nil {
err = er
return nil, false
}
return hs, true
}, 5)
img := GetCustomHeaderImgFn(h)
err = h.Err()
if err != nil {
logs.Error(err, "获取页眉背景图失败")
return

View File

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

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() {
d.ginH["totalCommentNum"] = 0
d.ginH["totalCommentPage"] = 1
@ -170,16 +179,17 @@ func DetailRender(h *Handle) {
if h.Stats != constraints.Ok {
return
}
d := h.Detail
d := h.GetDetailHandle()
d.PasswordProject()
d.RenderComment()
d.ginH["post"] = d.Post
}
func Detail(h *Handle) {
err := h.Detail.BuildDetailData()
d := h.GetDetailHandle()
err := d.BuildDetailData()
if err != nil {
h.Detail.SetErr(err)
d.SetErr(err)
}
h.SetData("scene", h.Scene())
}
@ -187,7 +197,7 @@ func Detail(h *Handle) {
func ReplyCommentJs(h *Handle) {
h.PushFooterScript(constraints.Detail, NewComponent("comment-reply.js", "", false, 10, func(h *Handle) string {
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>`
}
return reply

View File

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

View File

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

View File

@ -71,14 +71,7 @@ var plainRouteParam = reload.Vars([]Plain{
if u == "" {
return false
}
users := reload.GetAnyValBys("usersIds", struct{}{},
func(_ struct{}) (map[uint64]string, bool) {
users, err := cache.GetAllUsername(h.C)
if err != nil {
return nil, true
}
return maps.Flip(users), true
})
users := GetUsersIds(h)
name, ok := users[str.ToInteger[uint64](u, 0)]
if !ok {
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) {
plainRouteParam.Store(p)
}

View File

@ -3,7 +3,6 @@ package wp
import (
"github.com/fthvgb1/wp-go/app/pkg/constraints"
"github.com/fthvgb1/wp-go/cache/reload"
"github.com/fthvgb1/wp-go/helper"
"github.com/fthvgb1/wp-go/helper/slice"
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) {
if _, ok := h.handlers[pipScene]; !ok {
h.handlers[pipScene] = make(map[string][]HandleCall)
v, ok := handlerss.Load(pipScene)
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) {
@ -65,27 +66,14 @@ func (h *Handle) PushDataHandler(scene string, fns ...HandleCall) {
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) {
key := keyFn(h, pipeScene)
handlers := reload.GetAnyValMapBy("pipeHandlers", key, h, func(h *Handle) ([]HandleCall, bool) {
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
})
handlers := pipeHandlerFn(key, h)
for _, handler := range handlers {
handler.Fn(h)
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 {
key := str.Join("pipekey", "-", pipScene, "-", h.scene, "-", h.Stats)
return h.DoActionFilter("pipeKey", key, pipScene)
}
var pipeInitFn = reload.BuildMapFn[string]("pipeInit", BuildPipe)
func Run(h *Handle, conf func(*Handle)) {
if !helper.GetContextVal(h.C, "inited", false) {
if !h.isInited {
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) {
p := GetFn[Pipe]("pipe", constraints.AllScene)
p = append(p, GetFn[Pipe]("pipe", h.scene)...)
pipes := slice.FilterAndMap(p, func(pipe Pipe) (Pipe, bool) {
func BuildPipe(scene string) func(*Handle) {
pipees := GetFn[Pipe]("pipe", constraints.AllScene)
pipees = append(pipees, GetFn[Pipe]("pipe", scene)...)
pipes := slice.FilterAndMap(pipees, func(pipe Pipe) (Pipe, bool) {
var ok bool
mut := reload.GetGlobeMutex()
mut.Lock()
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 {
pipe, ok = fn(pipe)
if !ok {
@ -132,7 +153,7 @@ func BuildPipeAndHandler(h *Handle) (func(*Handle), bool) {
arr := slice.Map(pipes, func(t Pipe) HandlePipeFn[*Handle] {
return t.Fn
})
return HandlePipe(NothingToDo, arr...), true
return HandlePipe(NothingToDo, arr...)
}
func MiddlewareKey(h *Handle, pipScene string) string {
@ -164,24 +185,30 @@ func PipeRender(h *Handle, renders map[string][]HandleCall, key string) (handler
// DeleteHandle 写插件的时候用
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
})
handleHooks.Store(pipeScene, v)
}
// ReplaceHandle 写插件的时候用
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 {
call.Fn = fn
}
return call, true
})
handleHooks.Store(pipeScene, v)
}
// HookHandle 写插件的时候用
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 {
@ -197,10 +224,10 @@ func (h *Handle) PipeHandleHook(name string, calls []HandleCall, m map[string][]
func InitPipe(h *Handle) {
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,
BuildPipe(constraints.PipeData, PipeKey, PipeDataHandle)))
BuildHandlers(constraints.PipeData, PipeKey, PipeDataHandle)))
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
})
}
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) {
requestURI := h.C.Request.RequestURI
rs, rrs := reload.GetAnyValBys("route",
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
})()
rs, rrs := RegRouteFn()()
v, ok := rs[requestURI]
if ok && slice.IsContained(v.Method, h.C.Request.Method) {
h.SetScene(v.Scene)
wp.Run(h, nil)
h.Abort()
return
}
for path, reg := range rrs {
@ -125,6 +127,7 @@ func ResolveRoute(h *wp.Handle) {
h.SetScene(rr.Scene)
h.C.Set("route", r)
wp.Run(h, nil)
h.Abort()
return
}
}

View File

@ -8,41 +8,41 @@ import (
"github.com/fthvgb1/wp-go/app/pkg/models"
"github.com/fthvgb1/wp-go/app/wpconfig"
"github.com/fthvgb1/wp-go/cache/reload"
"github.com/fthvgb1/wp-go/helper/maps"
"github.com/fthvgb1/wp-go/helper/slice"
str "github.com/fthvgb1/wp-go/helper/strings"
)
func (h *Handle) StickPosts() []models.Posts {
return reload.GetAnyValBys("stickPostsSlice", h, func(h *Handle) (r []models.Posts, ok bool) {
v := wpconfig.GetOption("sticky_posts")
if v == "" {
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
var GetStickPosts = reload.BuildValFnWithConfirm("stickPostsSlice", ParseStickPosts)
func ParseStickPosts(h *Handle) (r []models.Posts, ok bool) {
v := wpconfig.GetOption("sticky_posts")
if v == "" {
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 {
return reload.GetAnyValBys("stickPostsMap", h, func(h *Handle) (map[uint64]models.Posts, bool) {
return slice.SimpleToMap(h.StickPosts(), func(v models.Posts) uint64 {
return v.Id
}), true
var GetStickMapPosts = reload.BuildValFn("stickPostsMap", StickMapPosts)
func StickMapPosts(h *Handle) map[uint64]models.Posts {
return slice.SimpleToMap(GetStickPosts(h), func(v models.Posts) uint64 {
return v.Id
})
}
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/helper/maps"
str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/safety"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"html/template"
@ -19,30 +20,26 @@ import (
)
type Handle struct {
Index *IndexHandle
Detail *DetailHandle
C *gin.Context
theme string
Session sessions.Session
ginH gin.H
password string
scene string
Code int
Stats string
templ string
components map[string]map[string][]Components[string]
componentHook map[string][]func(Components[string]) (Components[string], bool)
themeMods wpconfig.ThemeMods
handlers map[string]map[string][]HandleCall
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
C *gin.Context
theme string
isInited bool
Session sessions.Session
ginH gin.H
password string
scene string
Code int
Stats string
templ string
themeMods wpconfig.ThemeMods
err error
abort bool
stopPipe bool
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 {
return h.theme
}
@ -55,20 +52,20 @@ func (h *Handle) SetScene(scene string) {
h.scene = scene
}
func (h *Handle) Components() map[string]map[string][]Components[string] {
return h.components
func (h *Handle) Components() *safety.Map[string, map[string][]Components[string]] {
return handleComponents
}
func (h *Handle) ComponentHook() map[string][]func(Components[string]) (Components[string], bool) {
return h.componentHook
func (h *Handle) ComponentHook() *safety.Map[string, []func(Components[string]) (Components[string], bool)] {
return handleComponentHook
}
func (h *Handle) Handlers() map[string]map[string][]HandleCall {
return h.handlers
func (h *Handle) Handlers() *safety.Map[string, map[string][]HandleCall] {
return handlerss
}
func (h *Handle) HandleHook() map[string][]func(HandleCall) (HandleCall, bool) {
return h.handleHook
func (h *Handle) HandleHook() *safety.Map[string, []func(HandleCall) (HandleCall, bool)] {
return handleHooks
}
func (h *Handle) SetTemplate(template *template.Template) {
@ -98,45 +95,48 @@ type HandleCall struct {
Name string
}
func InitHandle(fn func(*Handle), h *Handle) {
var inited = false
hh := reload.GetAnyValBys("themeArgAndConfig", h, func(h *Handle) (Handle, bool) {
h.components = make(map[string]map[string][]Components[string])
h.componentsArgs = make(map[string]any)
h.componentFilterFn = make(map[string][]func(*Handle, string, ...any) string)
h.handlers = make(map[string]map[string][]HandleCall)
h.handleHook = make(map[string][]func(HandleCall) (HandleCall, bool))
h.ginH = gin.H{}
fnMap.Flush()
fnHook.Flush()
fn(h)
v := apply.UsePlugins()
pluginFn, ok := v.(func(*Handle))
if ok {
pluginFn(h)
}
h.C.Set("inited", true)
inited = true
return *h, true
})
func SetConfigHandle(a ...any) Handle {
configFn := a[0].(func(*Handle))
hh := a[1].(*Handle)
h := &Handle{}
mut := reload.GetGlobeMutex()
mut.Lock()
defer mut.Unlock()
handleComponents.Flush()
componentsArgs.Flush()
handleComponentHook.Flush()
componentFilterFns.Flush()
handlerss.Flush()
handleHooks.Flush()
h.ginH = gin.H{}
fnMap.Flush()
fnHook.Flush()
h.C = hh.C
h.theme = hh.theme
h.template = hh.template
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["calPostClass"] = postClass(h)
h.ginH["calBodyClass"] = bodyClass(h)
h.ginH["customLogo"] = customLogo(h)
if inited {
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)
h.isInited = true
}
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 {
ma = reload.FnVal(str.Join("paginationCache-", name, "-maxNum"), maxNum, nil)
ma = reload.BuildFnVal(str.Join("paginationCache-", name, "-maxNum"), maxNum, 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)
mapCache.Store(name, p)
@ -215,7 +215,7 @@ func buildLockFn[K comparable](args ...any) cache.LockFn[K] {
}
loFn = helper.ParseArgs(loFn, args...)
if name != "" {
loFn = reload.FnVal(str.Join("cachesLocksNum-", name), num, loFn)
loFn = reload.BuildFnVal(str.Join("cachesLocksNum-", name), num, loFn)
}
if lockFn == nil {
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 == "" {
return
}
fn := reload.FnVal(str.Join("cacheManger-", name, "-expiredTime"), expireTime, expireTimeFn)
fn := reload.BuildFnVal(str.Join("cacheManger-", name, "-expiredTime"), expireTime, expireTimeFn)
c.SetExpiredTime(fn)
}
func ChangeExpireTime(t time.Duration, coverConf bool, name ...string) {
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] {
tFn = reload.FnVal(name, cycleTime, tFn)
tFn = reload.BuildFnVal(name, cycleTime, tFn)
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()
batchFn = func(ctx context.Context, arr []string, a ...any) (map[string]string, error) {
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
}), nil
}
@ -69,7 +69,7 @@ func TestMapCache_Flush(t *testing.T) {
}
ca := *NewMapCache[string, string](NewMemoryMapCache[string, string](func() time.Duration {
return time.Second
}), fn, nil)
}), fn, nil, nil, nil)
_, _ = ca.GetCache(ct, "aa", time.Second, ct, "aa")
tests := []testCase[string, string]{
{

373
cache/reload/reload.go vendored
View File

@ -14,32 +14,47 @@ type queue struct {
name string
}
var calls = safety.NewSlice(make([]queue, 0))
var callsM = safety.NewMap[string, func()]()
var mut = &sync.Mutex{}
var anyMap = safety.NewMap[string, any]()
func GetGlobeMutex() *sync.Mutex {
return mut
}
type safetyVar[T, A any] struct {
Val *safety.Var[val[T]]
mutex sync.Mutex
var waitReloadCalls = safety.NewSlice(make([]queue, 0))
var callMap = safety.NewMap[string, func()]()
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 {
v T
ok bool
counter number.Counter[int]
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
type SafetyMap[K comparable, V, A any] struct {
Val *safety.Map[K, V]
Mutex sync.Mutex
}
var safetyMaps = safety.NewMap[string, any]()
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) {
fn, ok := flushMapFn.Load(namespace)
// GetValMap can get stored map value with namespace which called BuildSafetyMap, BuildMapFnWithConfirm, BuildMapFn, BuildMapFnWithAnyParams
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 {
return
}
@ -48,7 +63,7 @@ func FlushMapVal[T any](namespace string, key ...T) {
func FlushAnyVal(namespaces ...string) {
for _, namespace := range namespaces {
fn, ok := callsM.Load(namespace)
fn, ok := callMap.Load(namespace)
if !ok {
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 {
m := safetyMapFn[K, V, A](namespace)
// BuildMapFnWithConfirm same as BuildMapFn
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 {
v, ok := m.val.Load(key)
v, ok := m.Val.Load(key)
if ok {
return v
}
m.mutex.Lock()
defer m.mutex.Unlock()
v, ok = m.val.Load(key)
m.Mutex.Lock()
defer m.Mutex.Unlock()
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 {
return v
}
v = fn(a)
m.val.Store(key, v)
m.Val.Store(key, v)
return v
}
}
func safetyMapFn[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])
} else {
safetyMapLock.Lock()
defer safetyMapLock.Unlock()
vv, ok = safetyMaps.Load(namespace)
// BuildMapFnWithAnyParams same as BuildMapFn use multiple params
func BuildMapFnWithAnyParams[K comparable, V any](namespace string, fn func(...any) V, a ...any) func(key K, a ...any) V {
m := BuildSafetyMap[K, V, any](namespace, a...)
return func(key K, a ...any) V {
v, ok := m.Val.Load(key)
if ok {
m = vv.(*safetyMap[K, V, A])
} 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)
return v
}
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
}
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...)
v, ok := m.val.Load(key)
m := BuildSafetyMap[K, V, A](namespace, args...)
v, ok := m.Val.Load(key)
if ok {
return v
}
m.mutex.Lock()
defer m.mutex.Unlock()
v, ok = m.val.Load(key)
m.Mutex.Lock()
defer m.Mutex.Unlock()
v, ok = m.Val.Load(key)
if ok {
return v
}
v, ok = fn(a)
if ok {
m.val.Store(key, v)
m.Val.Store(key, v)
}
return v
}
func anyVal[T, A any](namespace string, counter bool, args ...any) *safetyVar[T, A] {
var vv *safetyVar[T, A]
func BuildAnyVal[T, A any](namespace string, counter bool, args ...any) *SafetyVar[T, A] {
var vv *SafetyVar[T, A]
vvv, ok := safetyMaps.Load(namespace)
if ok {
vv = vvv.(*safetyVar[T, A])
vv = vvv.(*SafetyVar[T, A])
} else {
safetyMapLock.Lock()
defer safetyMapLock.Unlock()
vvv, ok = safetyMaps.Load(namespace)
if ok {
vv = vvv.(*safetyVar[T, A])
vv = vvv.(*SafetyVar[T, A])
} else {
v := val[T]{}
if counter {
v.counter = number.Counters[int]()
}
vv = &safetyVar[T, A]{safety.NewVar(v), sync.Mutex{}}
v := Val[T]{}
vv = &SafetyVar[T, A]{safety.NewVar(v), sync.Mutex{}}
ord, _ := parseArgs(args...)
Push(func() {
vv.Val.Flush()
@ -153,53 +217,117 @@ func anyVal[T, A any](namespace string, counter bool, args ...any) *safetyVar[T,
return vv
}
func GetAnyValBy[T, A any](namespace string, a A, fn func(A) (T, bool), args ...any) T {
var vv = anyVal[T, A](namespace, true, args...)
var ok bool
func GetAnyValBys[T, A any](namespace string, a A, fn func(A) (T, bool), args ...any) T {
var vv = BuildAnyVal[T, A](namespace, false, args...)
v := vv.Val.Load()
if v.ok {
return v.v
if v.Ok {
return v.V
}
vv.mutex.Lock()
defer vv.mutex.Unlock()
vv.Mutex.Lock()
defer vv.Mutex.Unlock()
v = vv.Val.Load()
if v.ok {
return v.v
if v.Ok {
return v.V
}
v.v, ok = fn(a)
if v.counter == nil {
v.counter = number.Counters[int]()
}
times := v.counter()
tryTimes := helper.ParseArgs(1, args...)
if ok || times >= tryTimes {
v.ok = true
vv.Val.Store(v)
}
return v.v
v.V, v.Ok = fn(a)
vv.Val.Store(v)
return v.V
}
func GetAnyValBys[T, A any](namespace string, a A, fn func(A) (T, bool), args ...any) T {
var vv = anyVal[T, A](namespace, false, args...)
v := vv.Val.Load()
if v.ok {
return v.v
// BuildValFnWithConfirm same as BuildValFn
//
// if give a int and value bigger than 1 will be a times which built fn called return false
func BuildValFnWithConfirm[T, A any](namespace string, fn func(A) (T, bool), args ...any) func(A) T {
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()
defer vv.mutex.Unlock()
v = vv.Val.Load()
if v.ok {
return v.v
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, 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
//
// args same as Push
//
// 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] {
ss := safety.NewVar(defaults)
ord, name := parseArgs(args...)
@ -261,37 +389,42 @@ func SafeMap[K comparable, T any](args ...any) *safety.Map[K, T] {
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) {
ord, name := parseArgs(a...)
calls.Append(queue{fn, ord, name})
waitReloadCalls.Append(queue{fn, ord, name})
if name != "" {
callsM.Store(name, fn)
callMap.Store(name, fn)
}
}
func Reload() {
callsM.Flush()
flushMapFn.Flush()
callll := calls.Load()
slice.SimpleSort(callll, slice.DESC, func(t queue) float64 {
mut.Lock()
defer mut.Unlock()
callMap.Flush()
deleteMapFn.Flush()
reloadCalls := waitReloadCalls.Load()
slice.SimpleSort(reloadCalls, slice.DESC, func(t queue) float64 {
return t.order
})
for _, call := range callll {
for _, call := range reloadCalls {
call.fn()
}
return
}
type Any[T any] struct {
fn func() T
v *safety.Var[T]
isUseManger *safety.Var[bool]
fn func() T
v *safety.Var[T]
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 {
fn = func() T {
return t
@ -301,23 +434,23 @@ func FnVal[T any](name string, t T, fn func() T) func() T {
}
p := safety.NewVar(t)
e := Any[T]{
fn: fn,
v: p,
isUseManger: safety.NewVar(false),
fn: fn,
v: p,
isManual: safety.NewVar(false),
}
Push(func() {
if !e.isUseManger.Load() {
if !e.isManual.Load() {
e.v.Store(fn())
}
})
anyMap.Store(name, e)
setFnVal.Store(name, e)
return func() T {
return e.v.Load()
}
}
func ChangeFnVal[T any](name string, val T, coverConf bool) {
v, ok := anyMap.Load(name)
func SetFnVal[T any](name string, val T, onlyManual bool) {
v, ok := setFnVal.Load(name)
if !ok {
return
}
@ -325,8 +458,8 @@ func ChangeFnVal[T any](name string, val T, coverConf bool) {
if !ok {
return
}
if coverConf && !vv.isUseManger.Load() {
vv.isUseManger.Store(true)
if onlyManual && !vv.isManual.Load() {
vv.isManual.Store(true)
}
vv.v.Store(val)
}

View File

@ -13,7 +13,7 @@ func TestFlushMapVal(t *testing.T) {
return 33, true
})
fmt.Println(v)
FlushMapVal("key", 2)
DeleteMapVal("key", 2)
v = GetAnyValMapBy("key", 2, struct{}{}, func(a struct{}) (int, bool) {
fmt.Println("xxxxx")
@ -32,15 +32,15 @@ func TestFlushMapVal(t *testing.T) {
func TestGetAnyMapFnBys(t *testing.T) {
var i int
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++
return a + 1
return a + 1, true
})
vv := v(1, 2)
vvv := v(2, 3)
fmt.Println(vv, vvv)
v(1, 2)
FlushMapVal("name", 2)
DeleteMapVal("name", 2)
v(2, 3)
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
}
func AnyAnyMap[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)
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)
for k, v := range m {
key, val, ok := fn(k, v)
if ok {

View File

@ -172,10 +172,10 @@ func Slice[T any](arr []T, offset, length int) (r []T) {
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)
for _, t := range arr {
k, v, ok := fn(t)
for i, t := range arr {
k, v, ok := fn(t, i)
if ok {
r[k] = v
}