about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--cmd/server/main.go9
-rw-r--r--flake.nix1
-rw-r--r--go.mod10
-rw-r--r--go.sum17
-rw-r--r--internal/nats/log.go27
-rw-r--r--internal/nats/nats.go66
6 files changed, 129 insertions, 1 deletions
diff --git a/cmd/server/main.go b/cmd/server/main.go
index 652ffa3..01b8c54 100644
--- a/cmd/server/main.go
+++ b/cmd/server/main.go
@@ -6,6 +6,7 @@ import (
 	"os"
 	"os/signal"
 
+	"go.alanpearce.eu/website/internal/nats"
 	"go.alanpearce.eu/website/internal/server"
 	"go.alanpearce.eu/x/log"
 
@@ -52,8 +53,16 @@ func main() {
 		}
 	}()
 
+	go func() {
+		err := nats.Start(log.Named("nats"))
+		if err != nil {
+			log.Warn("could not start NATS server", "error", err)
+		}
+	}()
+
 	<-ctx.Done()
 	log.Debug("calling stop")
 	<-sv.Stop()
+	nats.Stop()
 	log.Debug("done")
 }
diff --git a/flake.nix b/flake.nix
index 34f4360..27dc552 100644
--- a/flake.nix
+++ b/flake.nix
@@ -30,6 +30,7 @@
             systemfd
             just
             modd
+            natscli
           ];
         in
         {
diff --git a/go.mod b/go.mod
index 7981a74..78456bd 100644
--- a/go.mod
+++ b/go.mod
@@ -21,12 +21,14 @@ require (
 	github.com/go-git/go-git/v5 v5.12.0
 	github.com/kevinpollet/nego v0.0.0-20211010160919-a65cd48cee43
 	github.com/libdns/powerdns v0.1.3
+	github.com/nats-io/nats-server/v2 v2.10.22
 	github.com/osdevisnot/sorvor v0.4.4
 	github.com/snabb/sitemap v1.0.4
 	github.com/stefanfritsch/goldmark-fences v1.0.0
 	github.com/yuin/goldmark v1.7.4
 	gitlab.com/tozd/go/errors v0.8.1
 	go.alanpearce.eu/x v0.0.0-20241203124832-a29434dba11a
+	go.uber.org/zap v1.27.0
 )
 
 require (
@@ -55,12 +57,18 @@ require (
 	github.com/gorilla/css v1.0.1 // indirect
 	github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
 	github.com/kevinburke/ssh_config v1.2.0 // indirect
+	github.com/klauspost/compress v1.17.11 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.9 // indirect
 	github.com/libdns/libdns v0.2.2 // indirect
 	github.com/mholt/acmez/v2 v2.0.3 // indirect
 	github.com/microcosm-cc/bluemonday v1.0.26 // indirect
 	github.com/miekg/dns v1.1.62 // indirect
+	github.com/minio/highwayhash v1.0.3 // indirect
 	github.com/mittwald/go-powerdns v0.6.6 // indirect
+	github.com/nats-io/jwt/v2 v2.5.8 // indirect
+	github.com/nats-io/nats.go v1.37.0 // indirect
+	github.com/nats-io/nkeys v0.4.7 // indirect
+	github.com/nats-io/nuid v1.0.1 // indirect
 	github.com/onsi/gomega v1.34.2 // indirect
 	github.com/pjbgf/sha1cd v0.3.0 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
@@ -74,13 +82,13 @@ require (
 	github.com/xanzy/ssh-agent v0.3.3 // indirect
 	github.com/zeebo/blake3 v0.2.4 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
-	go.uber.org/zap v1.27.0 // indirect
 	golang.org/x/crypto v0.29.0 // indirect
 	golang.org/x/mod v0.22.0 // indirect
 	golang.org/x/net v0.31.0 // indirect
 	golang.org/x/sync v0.9.0 // indirect
 	golang.org/x/sys v0.27.0 // indirect
 	golang.org/x/text v0.20.0 // indirect
+	golang.org/x/time v0.7.0 // indirect
 	golang.org/x/tools v0.27.0 // indirect
 	gopkg.in/warnings.v0 v0.1.2 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 7c12d1a..fd0709f 100644
--- a/go.sum
+++ b/go.sum
@@ -114,6 +114,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF
 github.com/kevinpollet/nego v0.0.0-20211010160919-a65cd48cee43 h1:Pdirg1gwhEcGjMLyuSxGn9664p+P8J9SrfMgpFwrDyg=
 github.com/kevinpollet/nego v0.0.0-20211010160919-a65cd48cee43/go.mod h1:ahLMuLCUyDdXqtqGyuwGev7/PGtO7r7ocvdwDuEN/3E=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
+github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
 github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
 github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -133,8 +135,20 @@ github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3r
 github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
 github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
 github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
+github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q=
+github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
 github.com/mittwald/go-powerdns v0.6.6 h1:yQcuszhl98+jJgELjD5ecfxCQWoshhnArexpwrwQxLY=
 github.com/mittwald/go-powerdns v0.6.6/go.mod h1:adWJ860laOgm14afg+7V0nCa5NQT37oEYe2HRhoS/CA=
+github.com/nats-io/jwt/v2 v2.5.8 h1:uvdSzwWiEGWGXf+0Q+70qv6AQdvcvxrv9hPM0RiPamE=
+github.com/nats-io/jwt/v2 v2.5.8/go.mod h1:ZdWS1nZa6WMZfFwwgpEaqBV8EPGVgOTDHN/wTbz0Y5A=
+github.com/nats-io/nats-server/v2 v2.10.22 h1:Yt63BGu2c3DdMoBZNcR6pjGQwk/asrKU7VX846ibxDA=
+github.com/nats-io/nats-server/v2 v2.10.22/go.mod h1:X/m1ye9NYansUXYFrbcDwUi/blHkrgHh2rgCJaakonk=
+github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE=
+github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
+github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
+github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
+github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
 github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
 github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
@@ -272,6 +286,7 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
 golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -292,6 +307,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
 golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
+golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
+golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
diff --git a/internal/nats/log.go b/internal/nats/log.go
new file mode 100644
index 0000000..cc9d1c2
--- /dev/null
+++ b/internal/nats/log.go
@@ -0,0 +1,27 @@
+package nats
+
+import (
+	"go.alanpearce.eu/x/log"
+	"go.uber.org/zap"
+)
+
+type Logger struct {
+	*zap.SugaredLogger
+}
+
+func adaptLogger(log *log.Logger) *Logger {
+	if log == nil {
+		panic("zl cannot be nil")
+	}
+	return &Logger{
+		log.GetLogger().Sugar(),
+	}
+}
+
+func (l *Logger) Tracef(format string, v ...any) {
+	l.Debugf(format, v...)
+}
+
+func (l *Logger) Noticef(format string, v ...any) {
+	l.Infof(format, v...)
+}
diff --git a/internal/nats/nats.go b/internal/nats/nats.go
new file mode 100644
index 0000000..9662868
--- /dev/null
+++ b/internal/nats/nats.go
@@ -0,0 +1,66 @@
+package nats
+
+import (
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/nats-io/nats-server/v2/server"
+	"gitlab.com/tozd/go/errors"
+	"go.alanpearce.eu/x/log"
+)
+
+const flyPrivateHostname = "fly-local-6pn"
+
+var srv *server.Server
+
+func Start(log *log.Logger) error {
+	var err error
+
+	appName := os.Getenv("FLY_APP_NAME")
+	if appName == "" {
+		log.Warn("no FLY_APP_NAME")
+
+		return nil
+	}
+	privateIP := os.Getenv("FLY_PRIVATE_IP")
+	if privateIP == "" {
+		log.Warn("no FLY_PRIVATE_IP")
+
+		return nil
+	}
+
+	hostname := fmt.Sprintf("%s.internal", appName)
+
+	opts := &server.Options{
+		ServerName: os.Getenv("FLY_MACHINE_ID"),
+		Host:       flyPrivateHostname,
+		Port:       4222,
+		Cluster: server.ClusterOpts{
+			Name:           appName,
+			Host:           flyPrivateHostname,
+			Port:           7221,
+			ConnectRetries: 60,
+		},
+		RoutesStr: "nats-route://" + hostname + ":7221",
+	}
+
+	srv, err = server.NewServer(opts)
+	if err != nil {
+		return errors.WithMessage(err, "could not start NATS server")
+	}
+
+	srv.SetLoggerV2(adaptLogger(log), false, false, false)
+	srv.Start()
+
+	if !srv.ReadyForConnections(4 * time.Second) {
+		log.Warn("server not ready")
+	}
+
+	return nil
+}
+
+func Stop() {
+	go srv.Shutdown()
+	srv.WaitForShutdown()
+}