cron passes main woo
parent
5ed296a3d2
commit
55c540e9c2
|
|
@ -1,9 +1,16 @@
|
||||||
package cron
|
package cron
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"show-rss/src/feeds"
|
"show-rss/src/feeds"
|
||||||
|
"show-rss/src/webhooks"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -44,7 +51,88 @@ func one(ctx context.Context, feed feeds.Feed) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("what do with %+v", items)
|
for _, item := range items {
|
||||||
|
if err := oneItem(ctx, feed, item); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return feed.Executed(ctx)
|
return feed.Executed(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func oneItem(ctx context.Context, feed feeds.Feed, item feeds.Item) error {
|
||||||
|
type Arg struct {
|
||||||
|
Feed feeds.Feed
|
||||||
|
Item feeds.Item
|
||||||
|
}
|
||||||
|
arg := Arg{
|
||||||
|
Feed: feed,
|
||||||
|
Item: item,
|
||||||
|
}
|
||||||
|
|
||||||
|
method, err := render(feed.Version.WebhookMethod, arg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
wurl, err := render(feed.Version.WebhookURL, arg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := render(feed.Version.WebhookBody, arg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var user *url.Userinfo
|
||||||
|
if u, _ := url.Parse(wurl); u.User != nil {
|
||||||
|
user = u.User
|
||||||
|
u.User = &url.Userinfo{}
|
||||||
|
wurl = u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if did, err := webhooks.Did(ctx, method, wurl, body); err != nil || did {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, wurl, strings.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
if user != nil {
|
||||||
|
u := user.Username()
|
||||||
|
p, _ := user.Password()
|
||||||
|
req.SetBasicAuth(u, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := http.Client{
|
||||||
|
Timeout: time.Minute,
|
||||||
|
Transport: &http.Transport{DisableKeepAlives: true},
|
||||||
|
}
|
||||||
|
resp, err := c.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
defer io.Copy(io.Discard, resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode > 204 {
|
||||||
|
b, _ := io.ReadAll(resp.Body)
|
||||||
|
return fmt.Errorf("failed %s %s w/ %s: (%d) %s", method, wurl, body, resp.StatusCode, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
return webhooks.Record(ctx, method, wurl, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func render(text string, arg any) (string, error) {
|
||||||
|
tmpl, err := template.New("render").Parse(text)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := bytes.NewBuffer(nil)
|
||||||
|
err = tmpl.Execute(b, arg)
|
||||||
|
return string(b.Bytes()), err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"show-rss/src/cmd/cron"
|
"show-rss/src/cmd/cron"
|
||||||
"show-rss/src/db"
|
"show-rss/src/db"
|
||||||
"show-rss/src/feeds"
|
"show-rss/src/feeds"
|
||||||
"slices"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -31,11 +30,14 @@ func TestOne(t *testing.T) {
|
||||||
Addr: ":10000",
|
Addr: ":10000",
|
||||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
gets = append(gets, r.URL.String())
|
gets = append(gets, r.URL.String())
|
||||||
t.Logf("serving fetch %s", gets[len(gets)-1])
|
rb, _ := io.ReadAll(r.Body)
|
||||||
|
t.Logf("serving fetch %s (%s)", gets[len(gets)-1], rb)
|
||||||
|
|
||||||
switch r.URL.Query().Get("idx") {
|
switch r.URL.Query().Get("idx") {
|
||||||
case "0":
|
case "0":
|
||||||
case "1":
|
case "1":
|
||||||
|
case "10":
|
||||||
|
case "11":
|
||||||
default:
|
default:
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
|
|
@ -47,8 +49,7 @@ func TestOne(t *testing.T) {
|
||||||
go s.ListenAndServe()
|
go s.ListenAndServe()
|
||||||
t.Cleanup(func() { s.Close() })
|
t.Cleanup(func() { s.Close() })
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
slices.Sort(gets)
|
if len(gets) != 1+2+2*2 { // healthcheck, (id=0,1) for feeds, 3 matching webhooks deduped down to 2
|
||||||
if len(gets) != 1+2+2+2 { // healthcheck, id=0+id=1 for each of 2 unrecycled ctx, id=0+id=1 for one across shared ctx
|
|
||||||
t.Errorf("didn't call urls: %+v", gets)
|
t.Errorf("didn't call urls: %+v", gets)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -65,7 +66,7 @@ func TestOne(t *testing.T) {
|
||||||
ctx := db.Test(t, ctx)
|
ctx := db.Test(t, ctx)
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
if _, err := feeds.Insert(ctx, fmt.Sprintf("%s?idx=%d", sURL, i), "* * * * *", "matches", http.MethodHead, fmt.Sprintf("%s?idx=1%d", sURL, i), "{{.Title}}"); err != nil {
|
if _, err := feeds.Insert(ctx, fmt.Sprintf("%s?idx=%d", sURL, i), "* * * * *", "matches", http.MethodHead, fmt.Sprintf("%s?idx=1%d", sURL, i), "{{.Item.Title}}"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue