notify.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package rss
  2. import (
  3. "context"
  4. "log"
  5. "net/http"
  6. "time"
  7. "github.com/mmcdole/gofeed"
  8. )
  9. // Notify on RSS change
  10. type Notify struct {
  11. feed string
  12. duration time.Duration
  13. ctx context.Context
  14. cancel context.CancelFunc
  15. }
  16. // Event from RSS
  17. type Event struct {
  18. ChanTitle string
  19. Title string
  20. Link string
  21. guid string
  22. }
  23. // New makes notifier for given rss feed. Checks for new items every duration
  24. func New(ctx context.Context, feed string, duration time.Duration) *Notify {
  25. res := Notify{feed: feed, duration: duration}
  26. res.ctx, res.cancel = context.WithCancel(ctx)
  27. log.Printf("[INFO] crate notifier for %q, %s", feed, duration)
  28. return &res
  29. }
  30. // Go starts notifier and returns events channel
  31. func (n *Notify) Go() <-chan Event {
  32. ch := make(chan Event)
  33. go func() {
  34. defer func() {
  35. close(ch)
  36. n.cancel()
  37. }()
  38. fp := gofeed.NewParser()
  39. fp.Client = &http.Client{Timeout: time.Second * 5}
  40. lastGUID := ""
  41. for {
  42. feedData, err := fp.ParseURL(n.feed)
  43. if err != nil {
  44. log.Printf("[WARN] failed to fetch from %s, %s", n.feed, err)
  45. time.Sleep(n.duration)
  46. continue
  47. }
  48. event := n.feedEvent(feedData)
  49. if lastGUID != event.guid {
  50. if lastGUID != "" {
  51. log.Printf("[DEBUG] new event %s", event.guid)
  52. ch <- event
  53. }
  54. lastGUID = event.guid
  55. }
  56. select {
  57. case <-n.ctx.Done():
  58. return
  59. case <-time.After(n.duration):
  60. }
  61. }
  62. }()
  63. return ch
  64. }
  65. // Shutdown notifier
  66. func (n *Notify) Shutdown() {
  67. n.cancel()
  68. <-n.ctx.Done()
  69. }
  70. func (n *Notify) feedEvent(feed *gofeed.Feed) (e Event) {
  71. e.ChanTitle = feed.Title
  72. if len(feed.Items) > 0 {
  73. e.Title = feed.Items[0].Title
  74. e.Link = feed.Items[0].Link
  75. e.guid = feed.Items[0].GUID
  76. }
  77. return e
  78. }