LamerAlert/sources/rss.go

119 lines
2.4 KiB
Go
Raw Permalink Normal View History

2019-12-24 12:20:27 +00:00
package sources
import (
"crypto/sha1"
"fmt"
"net/http"
"time"
pubsub "github.com/alash3al/go-pubsub"
"github.com/gorilla/mux"
"github.com/mmcdole/gofeed"
"github.com/rs/zerolog/log"
"code.chrissexton.org/cws/lameralert/config"
"code.chrissexton.org/cws/lameralert/event"
)
type RSS struct {
broker *pubsub.Broker
router *mux.Router
config *config.Config
configRoot string
url string
name string
}
func NewRSS(c *config.Config, r *mux.Router, name, url string) *RSS {
rss := RSS{
broker: pubsub.NewBroker(),
router: r,
config: c,
url: url,
name: name,
configRoot: fmt.Sprintf("rss.%s", name),
}
go rss.serve()
return &rss
}
func (rss *RSS) GetSender() *pubsub.Broker {
return rss.broker
}
func (rss *RSS) GetTopics() []string {
return []string{rss.name}
}
func (rss *RSS) pingHard(w http.ResponseWriter, r *http.Request) {
rss.check(true)
http.Error(w, "", http.StatusNoContent)
}
func (rss *RSS) ping(w http.ResponseWriter, r *http.Request) {
rss.check(false)
http.Error(w, "", http.StatusNoContent)
}
func (rss *RSS) serve() {
rss.router.HandleFunc("/force", rss.pingHard)
rss.router.HandleFunc("", rss.ping)
for {
wait := rss.config.GetInt(rss.configRoot+".wait", 900)
t := time.NewTimer(time.Duration(wait) * time.Second)
log.Debug().Msgf("%s waiting %v", rss.configRoot+".wait", wait)
<-t.C
log.Debug().Msgf("%s checking after %v", rss.name, wait)
rss.check(false)
}
}
func in(item string, slice []string) bool {
for _, it := range slice {
if item == it {
return true
}
}
return false
}
func hash(item string) string {
return fmt.Sprintf("%x", sha1.Sum([]byte(item)))
}
func (rss *RSS) check(force bool) {
fp := gofeed.NewParser()
feed, err := fp.ParseURL(rss.url)
if err != nil {
log.Error().Err(err).Msg("error getting RSS")
return
}
cache := rss.config.GetStringSlice(rss.configRoot+".cache", []string{})
newCache := []string{}
if force {
cache = []string{}
}
for _, it := range feed.Items {
h := hash(it.Title + it.Description)
newCache = append(newCache, h)
if !in(h, cache) {
payload := map[string]string{
"title": it.Title,
"description": it.Description,
"content": it.Content,
"published": it.Published,
}
ev := event.Event{
Time: time.Now(),
Payload: payload,
}
rss.broker.Broadcast(ev, rss.name)
}
}
rss.config.Set(rss.configRoot+".cache", newCache)
}