119 lines
2.4 KiB
Go
119 lines
2.4 KiB
Go
|
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)
|
||
|
}
|