完善post feed及加缓存

This commit is contained in:
xing 2022-10-07 22:27:34 +08:00
parent 05ddebd012
commit 7c4f4f10fc
5 changed files with 153 additions and 39 deletions

View File

@ -6,24 +6,32 @@ import (
"github/fthvgb1/wp-go/actions/common" "github/fthvgb1/wp-go/actions/common"
"github/fthvgb1/wp-go/cache" "github/fthvgb1/wp-go/cache"
"github/fthvgb1/wp-go/helper" "github/fthvgb1/wp-go/helper"
"github/fthvgb1/wp-go/logs"
"github/fthvgb1/wp-go/models" "github/fthvgb1/wp-go/models"
"github/fthvgb1/wp-go/plugins" "github/fthvgb1/wp-go/plugins"
"github/fthvgb1/wp-go/rss2" "github/fthvgb1/wp-go/rss2"
"net/http" "net/http"
"strconv"
"strings" "strings"
"time" "time"
) )
var feedCache = cache.NewSliceCache[string](feed, time.Hour) var feedCache = cache.NewSliceCache[string](feed, time.Hour)
var postFeedCache = cache.NewMapCacheByFn[string, string](postFeed, time.Hour)
var tmp = "Mon, 02 Jan 2006 15:04:05 GMT" var tmp = "Mon, 02 Jan 2006 15:04:05 GMT"
var templateRss rss2.Rss2
func FeedCached(c *gin.Context) { func InitFeed() {
if !isCacheExpired(c, feedCache.SetTime()) { templateRss = rss2.Rss2{
c.Status(http.StatusNotModified) Title: models.Options["blogname"],
c.Abort() AtomLink: fmt.Sprintf("%s/feed", models.Options["home"]),
return Link: models.Options["siteurl"],
Description: models.Options["blogdescription"],
Language: "zh-CN",
UpdatePeriod: "hourly",
UpdateFrequency: 1,
Generator: models.Options["home"],
} }
c.Next()
} }
func isCacheExpired(c *gin.Context, lastTime time.Time) bool { func isCacheExpired(c *gin.Context, lastTime time.Time) bool {
@ -41,19 +49,11 @@ func isCacheExpired(c *gin.Context, lastTime time.Time) bool {
} }
func Feed(c *gin.Context) { func Feed(c *gin.Context) {
s, err := feedCache.GetCache(c, time.Second, c) if !isCacheExpired(c, feedCache.SetTime()) {
if err != nil { c.Status(http.StatusNotModified)
c.Status(http.StatusInternalServerError) } else {
c.Abort() setFeed(feedCache, c)
c.Error(err)
return
} }
lastTimeGMT := feedCache.SetTime().Format(tmp)
eTag := helper.StringMd5(lastTimeGMT)
c.Header("Content-Type", "application/rss+xml; charset=UTF-8")
c.Header("Last-Modified", lastTimeGMT)
c.Header("ETag", eTag)
c.String(http.StatusOK, s[0])
} }
func feed(arg ...any) (xml []string, err error) { func feed(arg ...any) (xml []string, err error) {
@ -66,19 +66,8 @@ func feed(arg ...any) (xml []string, err error) {
if err != nil { if err != nil {
return return
} }
rs := rss2.Rss2{ rs := templateRss
Title: models.Options["blogname"], rs.LastBuildDate = time.Now().Format(time.RFC1123Z)
AtomLink: fmt.Sprintf("%s/feed", models.Options["home"]),
Link: models.Options["siteurl"],
Description: models.Options["blogdescription"],
LastBuildDate: time.Now().Format(time.RFC1123Z),
Language: "zh-CN",
UpdatePeriod: "hourly",
UpdateFrequency: 1,
Generator: models.Options["home"],
Items: nil,
}
rs.Items = helper.SliceMap(posts, func(t models.WpPosts) rss2.Item { rs.Items = helper.SliceMap(posts, func(t models.WpPosts) rss2.Item {
desc := "无法提供摘要。这是一篇受保护的文章。" desc := "无法提供摘要。这是一篇受保护的文章。"
common.PasswordProjectTitle(&t) common.PasswordProjectTitle(&t)
@ -112,3 +101,104 @@ func feed(arg ...any) (xml []string, err error) {
xml = []string{rs.GetXML()} xml = []string{rs.GetXML()}
return return
} }
func setFeed(sliceCache *cache.SliceCache[string], c *gin.Context) {
s, err := sliceCache.GetCache(c, time.Second, c)
if err != nil {
c.Status(http.StatusInternalServerError)
c.Abort()
c.Error(err)
return
}
lastTimeGMT := sliceCache.SetTime().Format(tmp)
eTag := helper.StringMd5(lastTimeGMT)
c.Header("Content-Type", "application/rss+xml; charset=UTF-8")
c.Header("Last-Modified", lastTimeGMT)
c.Header("ETag", eTag)
c.String(http.StatusOK, s[0])
}
func PostFeed(c *gin.Context) {
id := c.Param("id")
if !isCacheExpired(c, postFeedCache.GetSetTime(id)) {
c.Status(http.StatusNotModified)
} else {
s, err := postFeedCache.GetCache(c, id, time.Second, c, id)
if err != nil {
c.Status(http.StatusInternalServerError)
c.Abort()
c.Error(err)
return
}
lastTimeGMT := postFeedCache.GetSetTime(id).Format(tmp)
eTag := helper.StringMd5(lastTimeGMT)
c.Header("Content-Type", "application/rss+xml; charset=UTF-8")
c.Header("Last-Modified", lastTimeGMT)
c.Header("ETag", eTag)
c.String(http.StatusOK, s)
}
}
func postFeed(arg ...any) (x string, err error) {
c := arg[0].(*gin.Context)
id := arg[1].(string)
Id := 0
if id != "" {
Id, err = strconv.Atoi(id)
if err != nil {
return
}
}
ID := uint64(Id)
maxId, err := common.GetMaxPostId(c)
logs.ErrPrintln(err, "get max post id")
if ID > maxId || err != nil {
return
}
post, err := common.GetPostAndCache(c, ID)
if post.Id == 0 || err != nil {
return
}
common.PasswordProjectTitle(&post)
comments, err := common.PostComments(c, post.Id)
if err != nil {
return
}
rs := templateRss
rs.Title = fmt.Sprintf("《%s》的评论", post.PostTitle)
rs.AtomLink = fmt.Sprintf("%s/p/%d/feed", models.Options["siteurl"], post.Id)
rs.Link = fmt.Sprintf("%s/p/%d", models.Options["siteurl"], post.Id)
rs.LastBuildDate = time.Now().Format(time.RFC1123Z)
if post.PostPassword != "" {
if len(comments) > 0 {
common.PasswdProjectContent(&post)
t := comments[len(comments)-1]
rs.Items = []rss2.Item{
{
Title: fmt.Sprintf("评价者:%s", t.CommentAuthor),
Link: fmt.Sprintf("%s/p/%d#comment-%d", models.Options["siteurl"], post.Id, t.CommentId),
Creator: t.CommentAuthor,
PubDate: t.CommentDateGmt.Format(time.RFC1123Z),
Guid: fmt.Sprintf("%s#comment-%d", post.Guid, t.CommentId),
Description: "评论受保护:要查看请输入密码。",
Content: post.PostContent,
},
}
}
} else {
rs.Items = helper.SliceMap(comments, func(t models.WpComments) rss2.Item {
return rss2.Item{
Title: fmt.Sprintf("评价者:%s", t.CommentAuthor),
Link: fmt.Sprintf("%s/p/%d#comment-%d", models.Options["siteurl"], post.Id, t.CommentId),
Creator: t.CommentAuthor,
PubDate: t.CommentDateGmt.Format(time.RFC1123Z),
Guid: fmt.Sprintf("%s#comment-%d", post.Guid, t.CommentId),
Content: t.CommentContent,
}
})
}
x = rs.GetXML()
return
}

8
cache/map.go vendored
View File

@ -30,6 +30,14 @@ func (m *MapCache[K, V]) SetCacheFunc(fn func(...any) (V, error)) {
m.setCacheFunc = fn m.setCacheFunc = fn
} }
func (m *MapCache[K, V]) GetSetTime(k K) (t time.Time) {
r, ok := m.data[k]
if ok {
t = r.setTime
}
return
}
func (m *MapCache[K, V]) SetCacheBatchFunc(fn func(...any) (map[K]V, error)) { func (m *MapCache[K, V]) SetCacheBatchFunc(fn func(...any) (map[K]V, error)) {
m.setBatchCacheFn = fn m.setBatchCacheFn = fn
} }

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"github/fthvgb1/wp-go/actions"
"github/fthvgb1/wp-go/actions/common" "github/fthvgb1/wp-go/actions/common"
"github/fthvgb1/wp-go/db" "github/fthvgb1/wp-go/db"
"github/fthvgb1/wp-go/models" "github/fthvgb1/wp-go/models"
@ -30,7 +31,7 @@ func init() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
actions.InitFeed()
common.InitActionsCommonCache() common.InitActionsCommonCache()
plugins.InitDigestCache() plugins.InitDigestCache()
go cronClearCache() go cronClearCache()

View File

@ -52,7 +52,8 @@ func SetupRouter() *gin.Engine {
r.GET("/p/date/:year/:month/page/:page", actions.Index) r.GET("/p/date/:year/:month/page/:page", actions.Index)
r.POST("/login", actions.Login) r.POST("/login", actions.Login)
r.GET("/p/:id", actions.Detail) r.GET("/p/:id", actions.Detail)
r.GET("/feed", actions.FeedCached, actions.Feed) r.GET("/p/:id/feed", actions.PostFeed)
r.GET("/feed", actions.Feed)
if helper.IsContainInArr(gin.Mode(), []string{gin.DebugMode, gin.TestMode}) { if helper.IsContainInArr(gin.Mode(), []string{gin.DebugMode, gin.TestMode}) {
pprof.Register(r, "dev/pprof") pprof.Register(r, "dev/pprof")
} }

View File

@ -42,9 +42,9 @@ var templateItems = `
{$comments} {$comments}
<dc:creator><![CDATA[{$author}]]></dc:creator> <dc:creator><![CDATA[{$author}]]></dc:creator>
<pubDate>{$pubDate}</pubDate> <pubDate>{$pubDate}</pubDate>
<category><![CDATA[{$category}]]></category> {$category}
<guid isPermaLink="false">{$guid}</guid> <guid isPermaLink="false">{$guid}</guid>
<description><![CDATA[{$description}]]></description> {$description}
<content:encoded><![CDATA[{$content}]]></content:encoded> <content:encoded><![CDATA[{$content}]]></content:encoded>
{$commentRss} {$commentRss}
{$commentNumber} {$commentNumber}
@ -105,12 +105,12 @@ func (i Item) GetXml() (xml string) {
for k, v := range map[string]string{ for k, v := range map[string]string{
"{$title}": i.Title, "{$title}": i.Title,
"{$link}": i.Link, "{$link}": i.Link,
"{$comments}": i.GetComments(), "{$comments}": i.getComments(),
"{$author}": i.Creator, "{$author}": i.Creator,
"{$pubDate}": i.PubDate, "{$pubDate}": i.PubDate,
"{$category}": i.Category, "{$category}": i.getCategory(),
"{$guid}": i.Guid, "{$guid}": i.Guid,
"{$description}": i.Description, "{$description}": i.getDescription(),
"{$content}": i.Content, "{$content}": i.Content,
"{$commentRss}": i.getCommentRss(), "{$commentRss}": i.getCommentRss(),
"{$commentNumber}": i.getSlashComments(), "{$commentNumber}": i.getSlashComments(),
@ -120,7 +120,21 @@ func (i Item) GetXml() (xml string) {
return return
} }
func (i Item) GetComments() string { func (i Item) getCategory() string {
r := ""
if i.Category != "" {
r = fmt.Sprintf("<category><![CDATA[%s]]></category>", i.CommentLink)
}
return r
}
func (i Item) getDescription() string {
r := ""
if i.Description != "" {
r = fmt.Sprintf("<description><![CDATA[%s]]></description>", i.Description)
}
return r
}
func (i Item) getComments() string {
r := "" r := ""
if i.CommentLink != "" { if i.CommentLink != "" {
r = fmt.Sprintf("<comments>%s</comments>", i.CommentLink) r = fmt.Sprintf("<comments>%s</comments>", i.CommentLink)