From 3d802ccbdd2993b1d19ba9ca0711db9dbc3a5c7f Mon Sep 17 00:00:00 2001
From: Garet Halliday <me@garet.holiday>
Date: Thu, 31 Aug 2023 20:33:33 -0500
Subject: [PATCH] close unix sockets on exit

---
 lib/gat/acceptor.go        |  7 ++++++
 lib/util/beforeexit/run.go | 48 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)
 create mode 100644 lib/util/beforeexit/run.go

diff --git a/lib/gat/acceptor.go b/lib/gat/acceptor.go
index c41574ba..4a445c6c 100644
--- a/lib/gat/acceptor.go
+++ b/lib/gat/acceptor.go
@@ -5,6 +5,7 @@ import (
 
 	"pggat2/lib/bouncer/frontends/v0"
 	"pggat2/lib/fed"
+	"pggat2/lib/util/beforeexit"
 )
 
 type Acceptor struct {
@@ -31,6 +32,12 @@ func Listen(network, address string, options frontends.AcceptOptions) (Acceptor,
 	if err != nil {
 		return Acceptor{}, err
 	}
+	if network == "unix" {
+		// unix sockets are not cleaned up if process is stopped but i really wish they were
+		beforeexit.Run(func() {
+			_ = listener.Close()
+		})
+	}
 	return Acceptor{
 		Listener: listener,
 		Options:  options,
diff --git a/lib/util/beforeexit/run.go b/lib/util/beforeexit/run.go
new file mode 100644
index 00000000..fae29643
--- /dev/null
+++ b/lib/util/beforeexit/run.go
@@ -0,0 +1,48 @@
+package beforeexit
+
+import (
+	"os"
+	"os/signal"
+	"syscall"
+
+	"github.com/google/uuid"
+
+	"pggat2/lib/util/maps"
+)
+
+var toRun maps.RWLocked[uuid.UUID, func()]
+
+// Run will register a func to run before exit on receiving an interrupt
+// The order that tasks are run is undefined.
+func Run(fn func()) uuid.UUID {
+	id := uuid.New()
+	toRun.Store(id, fn)
+	return id
+}
+
+func Cancel(id uuid.UUID) {
+	toRun.Delete(id)
+}
+
+func init() {
+	c := make(chan os.Signal, 2)
+	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
+
+	go func() {
+		<-c
+
+		toRun.Range(func(_ uuid.UUID, fn func()) bool {
+			// ignore any panics in funcs
+			func() {
+				defer func() {
+					recover()
+				}()
+				fn()
+			}()
+
+			return true
+		})
+
+		os.Exit(1)
+	}()
+}
-- 
GitLab