diff --git a/actions/common/common.go b/actions/common/common.go index dba736a..ce51051 100644 --- a/actions/common/common.go +++ b/actions/common/common.go @@ -5,18 +5,15 @@ import ( "database/sql" "fmt" "github/fthvgb1/wp-go/cache" + "github/fthvgb1/wp-go/logs" "github/fthvgb1/wp-go/models" "github/fthvgb1/wp-go/vars" - "log" "strconv" - "strings" "sync" "time" ) -var PostsCache sync.Map -var PostContextCache sync.Map - +var postContextCache *cache.MapCache[uint64, PostContext] var archivesCaches *Arch var categoryCaches *cache.SliceCache[models.WpTermsMy] var recentPostsCaches *cache.SliceCache[models.WpPosts] @@ -29,6 +26,9 @@ func InitActionsCommonCache() { mutex: &sync.Mutex{}, setCacheFunc: archives, } + + postContextCache = cache.NewMapCache[uint64, PostContext](getPostContext, vars.Conf.ContextPostCacheTime) + postsCache = cache.NewMapBatchCache[uint64, models.WpPosts](getPosts, time.Hour) categoryCaches = cache.NewSliceCache[models.WpTermsMy](categories, vars.Conf.CategoryCacheTime) @@ -52,7 +52,7 @@ func (c *Arch) getArchiveCache() []models.PostArchive { if l > 0 && c.month != m || l < 1 { r, err := c.setCacheFunc() if err != nil { - log.Printf("set cache err[%s]", err) + logs.ErrPrintln(err, "set cache err[%s]") return nil } c.mutex.Lock() @@ -64,10 +64,8 @@ func (c *Arch) getArchiveCache() []models.PostArchive { } type PostContext struct { - Prev models.WpPosts - Next models.WpPosts - expireTime time.Duration - setTime time.Time + prev models.WpPosts + next models.WpPosts } func PostComments(ctx context.Context, Id uint64) ([]models.WpComments, error) { @@ -86,7 +84,8 @@ func postComments(args ...any) ([]models.WpComments, error) { } func RecentComments(ctx context.Context) (r []models.WpComments) { - r, _ = recentCommentsCaches.GetCache(ctx, time.Second) + r, err := recentCommentsCaches.GetCache(ctx, time.Second) + logs.ErrPrintln(err, "get recent comment") return } func recentComments(...any) (r []models.WpComments, err error) { @@ -98,48 +97,30 @@ func recentComments(...any) (r []models.WpComments, err error) { }, 5) } -func getMonthPost(args ...any) ([]models.WpPosts, error) { - y := args[0].(string) - m := args[1].(string) - where := models.SqlBuilder{ - {"post_type", "in", ""}, - {"post_status", "in", ""}, - {"month(post_date)", m}, - {"year(post_date)", y}, +func GetContextPost(ctx context.Context, id uint64, date time.Time) (prev, next models.WpPosts, err error) { + postCtx, err := postContextCache.GetCache(ctx, id, time.Second, date) + if err != nil { + return models.WpPosts{}, models.WpPosts{}, err } - return models.Find[models.WpPosts](where, "ID", "", - models.SqlBuilder{{"post_date", "asc"}}, - nil, 0, []any{"post"}, []any{"publish"}, - ) -} - -func GetContextPost(id uint64, t time.Time) (prev, next models.WpPosts, err error) { - post, ok := PostContextCache.Load(id) - if ok { - c := post.(PostContext) - isExp := c.expireTime/time.Second+time.Duration(c.setTime.Unix()) < time.Duration(time.Now().Unix()) - if !isExp && (c.Prev.Id > 0 || c.Next.Id > 0) { - return c.Prev, c.Next, nil - } - } - prev, next, err = getPostContext(t) - post = PostContext{ - Prev: prev, - Next: next, - expireTime: vars.Conf.ContextPostCacheTime, - setTime: time.Now(), - } - PostContextCache.Store(id, post) + prev = postCtx.prev + next = postCtx.next return } -func getPostContext(t time.Time) (prev, next models.WpPosts, err error) { - next, err = models.FirstOne[models.WpPosts](models.SqlBuilder{ +func getPostContext(arg ...any) (r PostContext, err error) { + t := arg[0].(time.Time) + next, err := models.FirstOne[models.WpPosts](models.SqlBuilder{ {"post_date", ">", t.Format("2006-01-02 15:04:05")}, {"post_status", "in", ""}, {"post_type", "post"}, }, "ID,post_title,post_password", nil, []any{"publish", "private"}) - prev, err = models.FirstOne[models.WpPosts](models.SqlBuilder{ + if err == sql.ErrNoRows { + err = nil + } + if err != nil { + return + } + prev, err := models.FirstOne[models.WpPosts](models.SqlBuilder{ {"post_date", "<", t.Format("2006-01-02 15:04:05")}, {"post_status", "in", ""}, {"post_type", "post"}, @@ -147,62 +128,12 @@ func getPostContext(t time.Time) (prev, next models.WpPosts, err error) { if err == sql.ErrNoRows { err = nil } - return -} - -func QueryAndSetPostCache(postIds []models.WpPosts) (err error) { - var all []uint64 - var needQuery []any - for _, wpPosts := range postIds { - all = append(all, wpPosts.Id) - if _, ok := PostsCache.Load(wpPosts.Id); !ok { - needQuery = append(needQuery, wpPosts.Id) - } + if err != nil { + return } - if len(needQuery) > 0 { - rawPosts, er := models.Find[models.WpPosts](models.SqlBuilder{{ - "Id", "in", "", - }}, "a.*,ifnull(d.name,'') category_name,ifnull(taxonomy,'') `taxonomy`", "", nil, models.SqlBuilder{{ - "a", "left join", "wp_term_relationships b", "a.Id=b.object_id", - }, { - "left join", "wp_term_taxonomy c", "b.term_taxonomy_id=c.term_taxonomy_id", - }, { - "left join", "wp_terms d", "c.term_id=d.term_id", - }}, 0, needQuery) - if er != nil { - err = er - return - } - postsMap := make(map[uint64]*models.WpPosts) - for i, post := range rawPosts { - v, ok := postsMap[post.Id] - if !ok { - v = &rawPosts[i] - } - if post.Taxonomy == "category" { - v.Categories = append(v.Categories, post.CategoryName) - } else if post.Taxonomy == "post_tag" { - v.Tags = append(v.Tags, post.CategoryName) - } - postsMap[post.Id] = v - } - for _, pp := range postsMap { - if len(pp.Categories) > 0 { - t := make([]string, 0, len(pp.Categories)) - for _, cat := range pp.Categories { - t = append(t, fmt.Sprintf(`%s`, cat, cat)) - } - pp.CategoriesHtml = strings.Join(t, "、") - } - if len(pp.Tags) > 0 { - t := make([]string, 0, len(pp.Tags)) - for _, cat := range pp.Tags { - t = append(t, fmt.Sprintf(``, cat, cat)) - } - pp.TagsHtml = strings.Join(t, "、") - } - PostsCache.Store(pp.Id, pp) - } + r = PostContext{ + prev: prev, + next: next, } return } @@ -218,7 +149,8 @@ func Archives() (r []models.PostArchive) { } func Categories(ctx context.Context) []models.WpTermsMy { - r, _ := categoryCaches.GetCache(ctx, time.Second) + r, err := categoryCaches.GetCache(ctx, time.Second) + logs.ErrPrintln(err, "get category ") return r } @@ -244,7 +176,8 @@ func categories(...any) (terms []models.WpTermsMy, err error) { } func RecentPosts(ctx context.Context) (r []models.WpPosts) { - r, _ = recentPostsCaches.GetCache(ctx, time.Second) + r, err := recentPostsCaches.GetCache(ctx, time.Second) + logs.ErrPrintln(err, "get recent post") return } func recentPosts(...any) (r []models.WpPosts, err error) { diff --git a/actions/common/posts.go b/actions/common/posts.go index 21d15c8..04bf3f7 100644 --- a/actions/common/posts.go +++ b/actions/common/posts.go @@ -2,16 +2,30 @@ package common import ( "context" + "fmt" "github/fthvgb1/wp-go/helper" "github/fthvgb1/wp-go/models" + "strings" "time" ) -func GetPostById(ctx context.Context, id uint64, ids ...uint64) (models.WpPosts, error) { +func GetPostAndCache(ctx context.Context, id uint64, ids ...uint64) (models.WpPosts, error) { return postsCache.GetCacheBatch(ctx, id, time.Second, ids) } +func GetPost(id uint64) models.WpPosts { + return postsCache.Get(id) +} + +func SetPostCache(ids []models.WpPosts) error { + var arg []uint64 + for _, posts := range ids { + arg = append(arg, posts.Id) + } + return postsCache.SetByBatchFn(arg) +} + func getPosts(ids ...any) (m map[uint64]models.WpPosts, err error) { m = make(map[uint64]models.WpPosts) id := ids[0].([]uint64) @@ -25,10 +39,38 @@ func getPosts(ids ...any) (m map[uint64]models.WpPosts, err error) { }, { "left join", "wp_terms d", "c.term_id=d.term_id", }}, 0, arg) - if err == nil { - for _, v := range rawPosts { - m[v.Id] = v + if err != nil { + return m, err + } + postsMap := make(map[uint64]models.WpPosts) + for i, post := range rawPosts { + v, ok := postsMap[post.Id] + if !ok { + v = rawPosts[i] } + if post.Taxonomy == "category" { + v.Categories = append(v.Categories, post.CategoryName) + } else if post.Taxonomy == "post_tag" { + v.Tags = append(v.Tags, post.CategoryName) + } + postsMap[post.Id] = v + } + for k, pp := range postsMap { + if len(pp.Categories) > 0 { + t := make([]string, 0, len(pp.Categories)) + for _, cat := range pp.Categories { + t = append(t, fmt.Sprintf(`%s`, cat, cat)) + } + pp.CategoriesHtml = strings.Join(t, "、") + } + if len(pp.Tags) > 0 { + t := make([]string, 0, len(pp.Tags)) + for _, cat := range pp.Tags { + t = append(t, fmt.Sprintf(``, cat, cat)) + } + pp.TagsHtml = strings.Join(t, "、") + } + m[k] = pp } return } diff --git a/actions/detail.go b/actions/detail.go index 6c66e25..fd9666a 100644 --- a/actions/detail.go +++ b/actions/detail.go @@ -6,6 +6,7 @@ import ( "github.com/gin-gonic/gin" "github/fthvgb1/wp-go/actions/common" "github/fthvgb1/wp-go/helper" + "github/fthvgb1/wp-go/logs" "github/fthvgb1/wp-go/models" "github/fthvgb1/wp-go/plugins" "math/rand" @@ -55,7 +56,7 @@ func Detail(c *gin.Context) { } } ID := uint64(Id) - post, err := common.GetPostById(c, ID, ID) + post, err := common.GetPostAndCache(c, ID, ID) if post.Id == 0 || err != nil { return } @@ -71,8 +72,10 @@ func Detail(c *gin.Context) { } plugins.ApplyPlugin(plugins.NewPostPlugin(c, plugins.Detail), &post) comments, err := common.PostComments(c, post.Id) + logs.ErrPrintln(err, "get post comment", post.Id) commentss := treeComments(comments) - prev, next, err := common.GetContextPost(post.Id, post.PostDate) + prev, next, err := common.GetContextPost(c, post.Id, post.PostDate) + logs.ErrPrintln(err, "get pre and next post", post.Id, post.PostDate) h["title"] = fmt.Sprintf("%s-%s", post.PostTitle, models.Options["blogname"]) h["post"] = post h["showComment"] = showComment diff --git a/actions/index.go b/actions/index.go index c8e137f..a20944b 100644 --- a/actions/index.go +++ b/actions/index.go @@ -181,23 +181,23 @@ func Index(c *gin.Context) { if len(postIds) < 1 && h.category != "" { h.titleL = "未找到页面" } - err = common.QueryAndSetPostCache(postIds) + err = common.SetPostCache(postIds) + if err != nil { + return + } pw := h.session.Get("post_password") plug := plugins.NewPostPlugin(c, h.scene) for i, v := range postIds { - post, _ := common.PostsCache.Load(v.Id) - pp := post.(*models.WpPosts) - px := *pp - postIds[i] = px + post := common.GetPost(v.Id) + postIds[i] = post common.PasswordProjectTitle(&postIds[i]) - if px.PostPassword != "" && pw != px.PostPassword { + if post.PostPassword != "" && pw != post.PostPassword { common.PasswdProjectContent(&postIds[i]) } else { plugins.ApplyPlugin(plug, &postIds[i]) } } for i, post := range recent { - if post.PostPassword != "" && pw != post.PostPassword { common.PasswdProjectContent(&recent[i]) } diff --git a/cache/map.go b/cache/map.go index a7110a0..cd08979 100644 --- a/cache/map.go +++ b/cache/map.go @@ -56,6 +56,20 @@ func (m *MapCache[K, V]) Set(k K, v V) { m.set(k, v) } +func (m *MapCache[K, V]) SetByBatchFn(params ...any) error { + m.mutex.Lock() + defer m.mutex.Unlock() + + r, err := m.setBatchCacheFn(params...) + if err != nil { + return err + } + for k, v := range r { + m.set(k, v) + } + return nil +} + func (m *MapCache[K, V]) set(k K, v V) { data, ok := m.data[k] t := time.Now() diff --git a/logs/log.go b/logs/log.go new file mode 100644 index 0000000..697c7a2 --- /dev/null +++ b/logs/log.go @@ -0,0 +1,26 @@ +package logs + +import ( + "log" + "strings" +) + +func ErrPrintln(err error, desc string, args ...any) { + s := strings.Builder{} + tmp := "%s err:[%s]" + if desc == "" { + tmp = "%s%s" + } + s.WriteString(tmp) + argss := []any{desc, err} + if len(args) > 0 { + s.WriteString(" args:") + for _, arg := range args { + s.WriteString("%v ") + argss = append(argss, arg) + } + } + if err != nil { + log.Printf(s.String(), argss...) + } +}