完善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/cache"
"github/fthvgb1/wp-go/helper"
"github/fthvgb1/wp-go/logs"
"github/fthvgb1/wp-go/models"
"github/fthvgb1/wp-go/plugins"
"github/fthvgb1/wp-go/rss2"
"net/http"
"strconv"
"strings"
"time"
)
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 templateRss rss2.Rss2
func FeedCached(c *gin.Context) {
if !isCacheExpired(c, feedCache.SetTime()) {
c.Status(http.StatusNotModified)
c.Abort()
return
func InitFeed() {
templateRss = rss2.Rss2{
Title: models.Options["blogname"],
AtomLink: fmt.Sprintf("%s/feed", models.Options["home"]),
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 {
@ -41,19 +49,11 @@ func isCacheExpired(c *gin.Context, lastTime time.Time) bool {
}
func Feed(c *gin.Context) {
s, err := feedCache.GetCache(c, time.Second, c)
if err != nil {
c.Status(http.StatusInternalServerError)
c.Abort()
c.Error(err)
return
if !isCacheExpired(c, feedCache.SetTime()) {
c.Status(http.StatusNotModified)
} else {
setFeed(feedCache, c)
}
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) {
@ -66,19 +66,8 @@ func feed(arg ...any) (xml []string, err error) {
if err != nil {
return
}
rs := rss2.Rss2{
Title: models.Options["blogname"],
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 := templateRss
rs.LastBuildDate = time.Now().Format(time.RFC1123Z)
rs.Items = helper.SliceMap(posts, func(t models.WpPosts) rss2.Item {
desc := "无法提供摘要。这是一篇受保护的文章。"
common.PasswordProjectTitle(&t)
@ -112,3 +101,104 @@ func feed(arg ...any) (xml []string, err error) {
xml = []string{rs.GetXML()}
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
}
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)) {
m.setBatchCacheFn = fn
}

View File

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

View File

@ -52,7 +52,8 @@ func SetupRouter() *gin.Engine {
r.GET("/p/date/:year/:month/page/:page", actions.Index)
r.POST("/login", actions.Login)
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}) {
pprof.Register(r, "dev/pprof")
}

View File

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