summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2022-05-20 17:24:52 -0600
committerBrian Picciano <mediocregopher@gmail.com>2022-05-20 17:24:52 -0600
commit99f8c1188ccd1580f58ad4c21cece040ed8e874c (patch)
tree1c4389da9129a9e7201ae6d4ad00e48c15e55170
parentb4ca8853a9085cb0231f2c4de25a1ec07ef150a0 (diff)
Add RSS feed generator
-rw-r--r--config.nix2
-rw-r--r--srv/default.nix7
-rw-r--r--srv/src/http/api.go21
-rw-r--r--srv/src/http/feed.go63
-rw-r--r--srv/src/mailinglist/mailinglist.go5
5 files changed, 89 insertions, 9 deletions
diff --git a/config.nix b/config.nix
index 674ba37..5f4bc13 100644
--- a/config.nix
+++ b/config.nix
@@ -1,11 +1,11 @@
{
runDir = "/tmp/mediocre-blog/run";
dataDir = "/tmp/mediocre-blog/data";
+ publicURL = "http://localhost:4000";
powSecret = "ssshhh";
mlSMTPAddr = "";
mlSMTPAuth = "";
- mlPublicURL = "http://localhost:4000";
httpListenProto = "tcp";
httpListenAddr = ":4000";
diff --git a/srv/default.nix b/srv/default.nix
index 7ca70e8..2f7d58c 100644
--- a/srv/default.nix
+++ b/srv/default.nix
@@ -16,7 +16,7 @@
# mailing list
export MEDIOCRE_BLOG_ML_SMTP_ADDR="${config.mlSMTPAddr}"
export MEDIOCRE_BLOG_ML_SMTP_AUTH="${config.mlSMTPAuth}"
- export MEDIOCRE_BLOG_ML_PUBLIC_URL="${config.mlPublicURL}"
+ export MEDIOCRE_BLOG_ML_PUBLIC_URL="${config.publicURL}"
# redis
export MEDIOCRE_BLOG_REDIS_PROTO=unix
@@ -26,8 +26,9 @@
export MEDIOCRE_BLOG_POW_SECRET="${config.powSecret}"
# http
- export MEDIOCRE_BLOG_LISTEN_PROTO="${config.httpListenProto}"
- export MEDIOCRE_BLOG_LISTEN_ADDR="${config.httpListenAddr}"
+ export MEDIOCRE_BLOG_HTTP_PUBLIC_URL="${config.publicURL}"
+ export MEDIOCRE_BLOG_HTTP_LISTEN_PROTO="${config.httpListenProto}"
+ export MEDIOCRE_BLOG_HTTP_LISTEN_ADDR="${config.httpListenAddr}"
export MEDIOCRE_BLOG_HTTP_AUTH_USERS='${builtins.toJSON config.httpAuthUsers}'
export MEDIOCRE_BLOG_HTTP_AUTH_RATELIMIT='${config.httpAuthRatelimit}'
'';
diff --git a/srv/src/http/api.go b/srv/src/http/api.go
index ab0e972..83ea8ab 100644
--- a/srv/src/http/api.go
+++ b/srv/src/http/api.go
@@ -10,7 +10,9 @@ import (
"html/template"
"net"
"net/http"
+ "net/url"
"os"
+ "strings"
"time"
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
@@ -40,6 +42,9 @@ type Params struct {
GlobalRoom chat.Room
UserIDCalculator *chat.UserIDCalculator
+ // PublicURL is the base URL which site visitors can navigate to.
+ PublicURL *url.URL
+
// ListenProto and ListenAddr are passed into net.Listen to create the
// API's listener. Both "tcp" and "unix" protocols are explicitly
// supported.
@@ -57,6 +62,9 @@ type Params struct {
// SetupCfg implement the cfg.Cfger interface.
func (p *Params) SetupCfg(cfg *cfg.Cfg) {
+
+ publicURLStr := cfg.String("http-public-url", "http://localhost:4000", "URL this service is accessible at")
+
cfg.StringVar(&p.ListenProto, "http-listen-proto", "tcp", "Protocol to listen for HTTP requests with")
cfg.StringVar(&p.ListenAddr, "http-listen-addr", ":4000", "Address/path to listen for HTTP requests on")
@@ -76,15 +84,21 @@ func (p *Params) SetupCfg(cfg *cfg.Cfg) {
return fmt.Errorf("unmarshaling -http-auth-ratelimit: %w", err)
}
+ *publicURLStr = strings.TrimSuffix(*publicURLStr, "/")
+ if p.PublicURL, err = url.Parse(*publicURLStr); err != nil {
+ return fmt.Errorf("parsing -http-public-url: %w", err)
+ }
+
return nil
})
}
// Annotate implements mctx.Annotator interface.
func (p *Params) Annotate(a mctx.Annotations) {
- a["listenProto"] = p.ListenProto
- a["listenAddr"] = p.ListenAddr
- a["authRatelimit"] = p.AuthRatelimit
+ a["httpPublicURL"] = p.PublicURL
+ a["httpListenProto"] = p.ListenProto
+ a["httpListenAddr"] = p.ListenAddr
+ a["httpAuthRatelimit"] = p.AuthRatelimit
}
// API will listen on the port configured for it, and serve HTTP requests for
@@ -218,6 +232,7 @@ func (a *api) handler() http.Handler {
mux.Handle("/static/", http.FileServer(http.FS(staticFS)))
mux.Handle("/follow", a.renderDumbTplHandler("follow.html"))
+ mux.Handle("/feed.xml", a.renderFeedHandler())
mux.Handle("/", a.renderIndexHandler())
var globalHandler http.Handler = mux
diff --git a/srv/src/http/feed.go b/srv/src/http/feed.go
new file mode 100644
index 0000000..8c0ef1c
--- /dev/null
+++ b/srv/src/http/feed.go
@@ -0,0 +1,63 @@
+package http
+
+import (
+ "fmt"
+ "net/http"
+ "path/filepath"
+
+ "github.com/gorilla/feeds"
+ "github.com/mediocregopher/blog.mediocregopher.com/srv/http/apiutil"
+)
+
+func (a *api) renderFeedHandler() http.Handler {
+
+ return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+
+ author := &feeds.Author{
+ Name: "mediocregopher",
+ }
+
+ publicURL := a.params.PublicURL.String()
+
+ feed := feeds.Feed{
+ Title: "Mediocre Blog",
+ Link: &feeds.Link{Href: publicURL + "/"},
+ Description: "A mix of tech, art, travel, and who knows what else.",
+ Author: author,
+ }
+
+ recentPosts, _, err := a.params.PostStore.WithOrderDesc().Get(0, 20)
+ if err != nil {
+ apiutil.InternalServerError(rw, r, fmt.Errorf("fetching recent posts: %w", err))
+ return
+ }
+
+ for _, post := range recentPosts {
+
+ if post.PublishedAt.After(feed.Updated) {
+ feed.Updated = post.PublishedAt
+ }
+
+ if post.LastUpdatedAt.After(feed.Updated) {
+ feed.Updated = post.LastUpdatedAt
+ }
+
+ postURL := publicURL + filepath.Join("/posts", post.ID)
+
+ feed.Items = append(feed.Items, &feeds.Item{
+ Title: post.Title,
+ Link: &feeds.Link{Href: postURL},
+ Author: author,
+ Description: post.Description,
+ Id: postURL,
+ Updated: post.LastUpdatedAt,
+ Created: post.PublishedAt,
+ })
+ }
+
+ if err := feed.WriteAtom(rw); err != nil {
+ apiutil.InternalServerError(rw, r, fmt.Errorf("writing atom feed: %w", err))
+ return
+ }
+ })
+}
diff --git a/srv/src/mailinglist/mailinglist.go b/srv/src/mailinglist/mailinglist.go
index fc6e014..28b44b0 100644
--- a/srv/src/mailinglist/mailinglist.go
+++ b/srv/src/mailinglist/mailinglist.go
@@ -57,8 +57,9 @@ func (p *Params) SetupCfg(cfg *cfg.Cfg) {
cfg.OnInit(func(ctx context.Context) error {
var err error
+ *publicURLStr = strings.TrimSuffix(*publicURLStr, "/")
if p.PublicURL, err = url.Parse(*publicURLStr); err != nil {
- return fmt.Errorf("parsing -public-url: %w", err)
+ return fmt.Errorf("parsing -ml-public-url: %w", err)
}
return nil
@@ -67,7 +68,7 @@ func (p *Params) SetupCfg(cfg *cfg.Cfg) {
// Annotate implements mctx.Annotator interface.
func (p *Params) Annotate(a mctx.Annotations) {
- a["publicURL"] = p.PublicURL
+ a["mlPublicURL"] = p.PublicURL
}
// New initializes and returns a MailingList instance using the given Params.