enable errata notices
This commit is contained in:
parent
91323758bc
commit
48d8279f63
169
errata.go
169
errata.go
@ -1,31 +1,129 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
// ParseErrata grabs all of the OpenBSD errata from an html page
|
||||
func ParseErrata(s string) ([]string, error) {
|
||||
var data []string
|
||||
resp, err := http.Get(s)
|
||||
// Errata stores all of the erratas grouped by date
|
||||
type Errata struct {
|
||||
ID int
|
||||
Type string
|
||||
Date time.Time
|
||||
Coverage string
|
||||
Desc string
|
||||
Link string
|
||||
}
|
||||
|
||||
// Errati is a collection of Errata
|
||||
type Errati struct {
|
||||
List []Errata
|
||||
Length int
|
||||
}
|
||||
|
||||
// By is the type of a "less" function that defines the ordering of its Planet arguments.
|
||||
type By func(p1, p2 *Errata) bool
|
||||
|
||||
// Sort is a method on the function type, By, that sorts the argument slice according to the function.
|
||||
func (by By) Sort(erratas []Errata) {
|
||||
es := &errataSorter{
|
||||
erratas: erratas,
|
||||
by: by,
|
||||
}
|
||||
sort.Sort(es)
|
||||
}
|
||||
|
||||
// errataSorter joins a By function and a slice of Errati to be sorted.
|
||||
type errataSorter struct {
|
||||
erratas []Errata
|
||||
by func(p1, p2 *Errata) bool // Closure used in the Less method.
|
||||
}
|
||||
|
||||
// Len is part of sort.Interface.
|
||||
func (s *errataSorter) Len() int {
|
||||
return len(s.erratas)
|
||||
}
|
||||
|
||||
// Swap is part of sort.Interface.
|
||||
func (s *errataSorter) Swap(i, j int) {
|
||||
s.erratas[i], s.erratas[j] = s.erratas[j], s.erratas[i]
|
||||
}
|
||||
|
||||
// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
|
||||
func (s *errataSorter) Less(i, j int) bool {
|
||||
return s.by(&s.erratas[i], &s.erratas[j])
|
||||
}
|
||||
|
||||
// ParseErrata does the actual parsing of html (poorly!)
|
||||
func ParseErrata(body io.Reader) (*Errati, error) {
|
||||
var data []Errata
|
||||
var errati = &Errati{}
|
||||
doc, err := html.Parse(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
doc, err := html.Parse(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var f func(*html.Node)
|
||||
f = func(node *html.Node) {
|
||||
if node.Type == html.ElementNode && node.Data == "strong" {
|
||||
if node.FirstChild != nil {
|
||||
data = append(data, node.FirstChild.Data)
|
||||
var e Errata
|
||||
var err error
|
||||
parts := strings.Split(node.FirstChild.Data, ": ")
|
||||
e.ID, err = strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
e.Type = parts[1]
|
||||
e.Date, err = time.Parse("January 02, 2006", parts[2])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: not this.
|
||||
|
||||
if node.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.FirstChild.Data != "" {
|
||||
e.Coverage = node.NextSibling.NextSibling.FirstChild.Data
|
||||
}
|
||||
|
||||
if node.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.Data != "" {
|
||||
e.Desc = node.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.Data
|
||||
e.Desc = strings.TrimRight(e.Desc, "\n")
|
||||
e.Desc = strings.TrimLeft(e.Desc, "\n")
|
||||
}
|
||||
|
||||
if node.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling != nil &&
|
||||
node.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling != nil {
|
||||
n := node.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling
|
||||
for _, a := range n.Attr {
|
||||
if a.Key == "href" {
|
||||
e.Link = a.Val
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data = append(data, e)
|
||||
errati.Length = errati.Length + 1
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -35,5 +133,48 @@ func ParseErrata(s string) ([]string, error) {
|
||||
}
|
||||
f(doc)
|
||||
|
||||
return data, nil
|
||||
byDate := func(p1, p2 *Errata) bool {
|
||||
return p1.Date.Unix() < p2.Date.Unix()
|
||||
}
|
||||
|
||||
By(byDate).Sort(data)
|
||||
errati.List = data
|
||||
|
||||
return errati, nil
|
||||
}
|
||||
|
||||
// ParseRemoteErrata grabs all of the OpenBSD errata from an html page
|
||||
func ParseRemoteErrata(s string) (*Errati, error) {
|
||||
resp, err := http.Get(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseErrata(resp.Body)
|
||||
}
|
||||
|
||||
// PrintErrata pretty prints an errata
|
||||
func PrintErrata(e *Errata) string {
|
||||
return fmt.Sprintf("%03d: %s: %s %s\n%s\n%s",
|
||||
e.ID,
|
||||
e.Type,
|
||||
e.Date.String(),
|
||||
e.Coverage,
|
||||
e.Desc,
|
||||
e.Link,
|
||||
)
|
||||
}
|
||||
|
||||
// PrintErrataMD pretty prints an errata in markdown
|
||||
//func PrintErrataMD(e *Errata) string {
|
||||
// return fmt.Sprintf("#%03d: %s: %s _%s_\n%s\n[A source code patch exists which remedies this problem.](%s)",
|
||||
// e.ID,
|
||||
// e.Type,
|
||||
// e.Date.String(),
|
||||
// e.Coverage,
|
||||
// e.Desc,
|
||||
// e.Link,
|
||||
// )
|
||||
//}
|
||||
|
@ -5,11 +5,11 @@ import (
|
||||
)
|
||||
|
||||
func TestParseErrata(t *testing.T) {
|
||||
got, err := ParseErrata("https://www.openbsd.org/errata66.html")
|
||||
got, err := ParseRemoteErrata("https://www.openbsd.org/errata66.html")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
l := len(got)
|
||||
l := len(got.List)
|
||||
if l == 0 {
|
||||
t.Errorf("errata count %d; want > 0", l)
|
||||
}
|
||||
|
37
main.go
37
main.go
@ -6,6 +6,8 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/gomatrix"
|
||||
@ -142,6 +144,41 @@ func main() {
|
||||
}
|
||||
})
|
||||
|
||||
go func() {
|
||||
errataCount := 0
|
||||
storeCount, _ := store.Get("errata_count")
|
||||
openbsdRelease, _ := store.Get("openbsd_release")
|
||||
errataCount, err = strconv.Atoi(storeCount)
|
||||
for {
|
||||
got, err := ParseRemoteErrata(
|
||||
fmt.Sprintf("https://www.openbsd.org/errata%s.html", openbsdRelease),
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
l := got.Length
|
||||
if l > errataCount {
|
||||
log.Println("Found new errata")
|
||||
alertRooms, _ := store.Get("errata_rooms")
|
||||
c := 0
|
||||
for _, errata := range got.List {
|
||||
if c+1 > errataCount {
|
||||
log.Printf("%03d: %s - %s\n", errata.ID, errata.Type, errata.Desc)
|
||||
for _, room := range strings.Split(alertRooms, ",") {
|
||||
log.Printf("sending errata %03d alert to '%s'\n", errata.ID, room)
|
||||
cli.SendNotice(room, PrintErrata(&errata))
|
||||
}
|
||||
}
|
||||
c = c + 1
|
||||
}
|
||||
errataCount = l
|
||||
}
|
||||
fmt.Printf("Setting errata_count to %d\n", l)
|
||||
store.Set("errata_count", string(l))
|
||||
time.Sleep(2 * time.Hour)
|
||||
}
|
||||
}()
|
||||
|
||||
syncer.OnEventType("m.room.message", func(ev *gomatrix.Event) {
|
||||
if ev.Sender == username {
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user