package handler import ( "encoding/xml" "net/http" "os" "time" "github.com/gin-gonic/gin" "gorm.io/gorm" "git.sundynix.cn/Blizzard/sundynix-site/server/internal/model" ) // RSSHandler 输出博客的 RSS 2.0 订阅源。 type RSSHandler struct { db *gorm.DB siteURL string } func NewRSSHandler(db *gorm.DB) *RSSHandler { siteURL := os.Getenv("SUNDYNIX_SITE_URL") if siteURL == "" { siteURL = "https://sundynix.com" } return &RSSHandler{db: db, siteURL: siteURL} } type rssItem struct { Title string `xml:"title"` Link string `xml:"link"` GUID string `xml:"guid"` Description string `xml:"description"` Category string `xml:"category,omitempty"` PubDate string `xml:"pubDate"` } type rssFeed struct { XMLName xml.Name `xml:"rss"` Version string `xml:"version,attr"` Channel struct { Title string `xml:"title"` Link string `xml:"link"` Description string `xml:"description"` Language string `xml:"language"` Items []rssItem `xml:"item"` } `xml:"channel"` } // Feed GET /rss.xml func (h *RSSHandler) Feed(c *gin.Context) { var posts []model.PostListItem err := h.db.Model(&model.Post{}). Where("published_at IS NOT NULL"). Order("published_at DESC"). Limit(50). Find(&posts).Error if err != nil { c.String(http.StatusInternalServerError, "feed unavailable") return } feed := rssFeed{Version: "2.0"} feed.Channel.Title = "sundynix agentix 博客" feed.Channel.Link = h.siteURL + "/blog" feed.Channel.Description = "事件驱动的 AI Agent 工作台 — 发布日志与工程笔记" feed.Channel.Language = "zh-cn" for _, p := range posts { link := h.siteURL + "/blog/" + p.Slug item := rssItem{ Title: p.Title, Link: link, GUID: link, Description: p.Summary, Category: p.Category, } if p.PublishedAt != nil { item.PubDate = p.PublishedAt.Format(time.RFC1123Z) } feed.Channel.Items = append(feed.Channel.Items, item) } c.Header("Content-Type", "application/rss+xml; charset=utf-8") c.String(http.StatusOK, xml.Header) if out, err := xml.MarshalIndent(feed, "", " "); err == nil { c.Writer.Write(out) } }