- commit
- bb7b4f2
- parent
- b2aa9b3
- author
- Eric Bower
- date
- 2026-01-08 22:13:26 -0500 EST
feat(pipe): web based rss feed
2 files changed,
+51,
-12
+41,
-2
1@@ -16,6 +16,7 @@ import (
2
3 "github.com/google/uuid"
4 "github.com/gorilla/websocket"
5+ "github.com/picosh/pico/pkg/db"
6 "github.com/picosh/pico/pkg/db/postgres"
7 "github.com/picosh/pico/pkg/shared"
8 "github.com/picosh/utils/pipe"
9@@ -386,10 +387,48 @@ func handlePipe() http.HandlerFunc {
10 }
11 }
12
13-func createMainRoutes(staticRoutes []shared.Route) []shared.Route {
14+func rssHandler(cfg *shared.ConfigSite, dbpool db.DB) http.HandlerFunc {
15+ return func(w http.ResponseWriter, r *http.Request) {
16+ apiToken, _ := url.PathUnescape(shared.GetField(r, 0))
17+ user, err := dbpool.FindUserByToken(apiToken)
18+ if err != nil {
19+ cfg.Logger.Error(
20+ "could not find user for token",
21+ "err", err.Error(),
22+ "token", apiToken,
23+ )
24+ http.Error(w, "invalid token", http.StatusNotFound)
25+ return
26+ }
27+ rss, err := MonitorRss(dbpool, user, cfg.Domain)
28+ if err != nil {
29+ cfg.Logger.Error(
30+ "error generating monitor rss feed",
31+ "err", err,
32+ "token", apiToken,
33+ )
34+ http.Error(w, "error generating monitor rss feed", http.StatusInternalServerError)
35+ return
36+ }
37+
38+ _, err = w.Write([]byte(rss))
39+ if err != nil {
40+ cfg.Logger.Error(
41+ "error with rss response writer",
42+ "err", err,
43+ "token", apiToken,
44+ )
45+ http.Error(w, "error generating monitor rss feederror with rss response writer", http.StatusInternalServerError)
46+ return
47+ }
48+ }
49+}
50+
51+func createMainRoutes(staticRoutes []shared.Route, cfg *shared.ConfigSite, dbpool db.DB) []shared.Route {
52 routes := []shared.Route{
53 shared.NewRoute("GET", "/", shared.CreatePageHandler("html/marketing.page.tmpl")),
54 shared.NewRoute("GET", "/check", shared.CheckHandler),
55+ shared.NewRoute("GET", "/rss/(.+)", rssHandler(cfg, dbpool)),
56 shared.NewRoute("GET", "/_metrics", promhttp.Handler().ServeHTTP),
57 }
58
59@@ -428,7 +467,7 @@ func StartApiServer() {
60 staticRoutes = shared.CreatePProfRoutes(staticRoutes)
61 }
62
63- mainRoutes := createMainRoutes(staticRoutes)
64+ mainRoutes := createMainRoutes(staticRoutes, cfg, db)
65 subdomainRoutes := staticRoutes
66
67 info := shared.NewPicoPipeClient()
+10,
-10
1@@ -93,7 +93,8 @@ func Middleware(handler *CliHandler) pssh.SSHServerMiddleware {
2 }
3 return next(sesh)
4 case "rss":
5- err := handler.rss(cliCmd, user)
6+ rss, err := MonitorRss(handler.DBPool, user, handler.Cfg.Domain)
7+ _, _ = fmt.Fprintln(sesh, rss)
8 if err != nil {
9 logger.Error("rss cmd", "err", err)
10 sesh.Fatal(err)
11@@ -542,20 +543,20 @@ func parseDuration(s string) (time.Duration, error) {
12 return time.ParseDuration(s)
13 }
14
15-func (handler *CliHandler) rss(cmd *CliCmd, user *db.User) error {
16+func MonitorRss(dbpool db.DB, user *db.User, domain string) (string, error) {
17 if user == nil {
18- return fmt.Errorf("access denied")
19+ return "", fmt.Errorf("access denied")
20 }
21
22- monitors, err := handler.DBPool.FindPipeMonitorsByUser(user.ID)
23+ monitors, err := dbpool.FindPipeMonitorsByUser(user.ID)
24 if err != nil {
25- return fmt.Errorf("failed to fetch monitors: %w", err)
26+ return "", fmt.Errorf("failed to fetch monitors: %w", err)
27 }
28
29 now := time.Now()
30 feed := &feeds.Feed{
31 Title: fmt.Sprintf("Pipe Monitors for %s", user.Name),
32- Link: &feeds.Link{Href: fmt.Sprintf("https://%s", handler.Cfg.Domain)},
33+ Link: &feeds.Link{Href: fmt.Sprintf("https://%s", domain)},
34 Description: "Alerts for pipe monitor status changes",
35 Author: &feeds.Author{Name: user.Name},
36 Created: now,
37@@ -567,7 +568,7 @@ func (handler *CliHandler) rss(cmd *CliCmd, user *db.User) error {
38 item := &feeds.Item{
39 Id: fmt.Sprintf("%s-%s-%d", user.ID, m.Topic, now.Unix()),
40 Title: fmt.Sprintf("ALERT: %s is unhealthy", m.Topic),
41- Link: &feeds.Link{Href: fmt.Sprintf("https://%s", handler.Cfg.Domain)},
42+ Link: &feeds.Link{Href: fmt.Sprintf("https://%s", domain)},
43 Description: err.Error(),
44 Created: now,
45 Updated: now,
46@@ -580,11 +581,10 @@ func (handler *CliHandler) rss(cmd *CliCmd, user *db.User) error {
47
48 rss, err := feed.ToRss()
49 if err != nil {
50- return fmt.Errorf("failed to generate RSS: %w", err)
51+ return "", fmt.Errorf("failed to generate RSS: %w", err)
52 }
53
54- _, _ = fmt.Fprint(cmd.sesh, rss)
55- return nil
56+ return rss, nil
57 }
58
59 func (handler *CliHandler) pub(cmd *CliCmd, topic string, clientID string) error {