diff --git a/feed.go b/feed.go new file mode 100644 index 0000000..fe48170 --- /dev/null +++ b/feed.go @@ -0,0 +1,14 @@ +package main + +type feed struct { + Title string `json:"title,omitempty"` + Link string `json:"link"` + Custom map[string]string `json:"custom,omitempty"` + Items []item `json:"items,omitempty"` +} + +type item struct { + Title string `json:"title"` + Link string `json:"link"` + Description string `json:"description"` +} diff --git a/main.go b/main.go index a22e4e1..d162f6b 100644 --- a/main.go +++ b/main.go @@ -20,9 +20,10 @@ type Config struct { } var ( - dbMap sync.Map + dbMap map[string]feed rssUrls Config upgrader = websocket.Upgrader{} + lock sync.RWMutex //go:embed static dirStatic embed.FS @@ -48,6 +49,8 @@ func init() { if err != nil { panic(err) } + + dbMap = make(map[string]feed) } func main() { @@ -73,15 +76,24 @@ func wsHandler(w http.ResponseWriter, r *http.Request) { log.Printf("Upgrade failed: %v", err) return } + defer conn.Close() for { for _, url := range rssUrls.Values { - feedJSON, ok := dbMap.Load(url) + lock.RLock() + cache, ok := dbMap[url] + lock.RUnlock() if !ok { log.Printf("Error getting feed from db is null %v", url) continue } - err = conn.WriteMessage(websocket.TextMessage, []byte(feedJSON.(string))) + data, err := json.Marshal(cache) + if err != nil { + log.Printf("json marshal failure: %s", err.Error()) + continue + } + + err = conn.WriteMessage(websocket.TextMessage, data) //错误直接关闭更新 if err != nil { log.Printf("Error sending message or Connection closed: %v", err) @@ -97,46 +109,62 @@ func wsHandler(w http.ResponseWriter, r *http.Request) { } func updateFeeds() { + var ( + tick = time.Tick(time.Duration(rssUrls.ReFresh) * time.Minute) + fp = gofeed.NewParser() + ) for { + formattedTime := time.Now().Format("2006-01-02 15:04:05") for _, url := range rssUrls.Values { - fp := gofeed.NewParser() - feed, err := fp.ParseURL(url) - if err != nil { - log.Printf("Error fetching feed: %v | %v", url, err) - continue - } - currentTime := time.Now() - formattedTime := currentTime.Format("2006-01-02 15:04:05") - feed.Custom = map[string]string{"lastupdate": formattedTime} - - feedJSON, err := json.Marshal(feed) - if err != nil { - log.Printf("Error marshaling feed: %v", err) - continue - } - dbMap.Store(url, string(feedJSON)) + go updateFeed(fp, url, formattedTime) } - time.Sleep(time.Duration(rssUrls.ReFresh) * time.Minute) + <-tick } } -func getFeedsHandler(w http.ResponseWriter, r *http.Request) { +func updateFeed(fp *gofeed.Parser, url, formattedTime string) { + result, err := fp.ParseURL(url) + if err != nil { + log.Printf("Error fetching feed: %v | %v", url, err) + return + } + //feed内容无更新时无需更新缓存 + if cache, ok := dbMap[url]; ok && + len(result.Items) > 0 && + len(cache.Items) > 0 && + result.Items[0].Link == cache.Items[0].Link { + return + } + customFeed := feed{ + Title: result.Title, + Link: result.Link, + Custom: map[string]string{"lastupdate": formattedTime}, + Items: make([]item, 0, len(result.Items)), + } + for _, v := range result.Items { + customFeed.Items = append(customFeed.Items, item{ + Link: v.Link, + Title: v.Title, + Description: v.Description, + }) + } + lock.Lock() + defer lock.Unlock() + dbMap[url] = customFeed +} - feeds := make([]gofeed.Feed, 0, len(rssUrls.Values)) +func getFeedsHandler(w http.ResponseWriter, r *http.Request) { + feeds := make([]feed, 0, len(rssUrls.Values)) for _, url := range rssUrls.Values { - feedJSON, ok := dbMap.Load(url) + lock.RLock() + cache, ok := dbMap[url] + lock.RUnlock() if !ok { log.Printf("Error getting feed from db is null %v", url) continue } - var feed gofeed.Feed - if err := json.Unmarshal([]byte(feedJSON.(string)), &feed); err != nil { - log.Printf("Error unmarshaling feed: %v", err) - continue - } - - feeds = append(feeds, feed) + feeds = append(feeds, cache) } w.Header().Set("Content-Type", "application/json")