aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.golangci.yaml1
-rw-r--r--config.go3
-rw-r--r--forge.scfg5
-rw-r--r--lmtp_server.go10
-rw-r--r--main.go130
5 files changed, 97 insertions, 52 deletions
diff --git a/.golangci.yaml b/.golangci.yaml
index 230efcd..760bb07 100644
--- a/.golangci.yaml
+++ b/.golangci.yaml
@@ -18,6 +18,7 @@ linters:
- nestif # e
- gocognit # e
- gocyclo # e
+ - dupl # e
- cyclop # e
- goconst # e
- funlen # e
diff --git a/config.go b/config.go
index 1973f3d..97e2588 100644
--- a/config.go
+++ b/config.go
@@ -31,6 +31,9 @@ var config struct {
Socket string `scfg:"socket"`
Execs string `scfg:"execs"`
} `scfg:"hooks"`
+ LMTP struct {
+ Socket string `scfg:"socket"`
+ } `scfg:"lmtp"`
Git struct {
RepoDir string `scfg:"repo_dir"`
} `scfg:"git"`
diff --git a/forge.scfg b/forge.scfg
index 5003b75..abf4f80 100644
--- a/forge.scfg
+++ b/forge.scfg
@@ -76,3 +76,8 @@ hooks {
# Where should hook executables be put?
execs /usr/libexec/lindenii/forge/hooks
}
+
+lmtp {
+ # On which UNIX domain socket should we listen for LMTP on?
+ socket /var/run/lindenii/forge/lmtp.sock
+}
diff --git a/lmtp_server.go b/lmtp_server.go
new file mode 100644
index 0000000..57f319a
--- /dev/null
+++ b/lmtp_server.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: AGPL-3.0-only
+// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>
+
+package main
+
+import "net"
+
+func serveLMTP(_ net.Listener) error {
+ return nil
+}
diff --git a/main.go b/main.go
index 90a0bac..75e187f 100644
--- a/main.go
+++ b/main.go
@@ -33,72 +33,98 @@ func main() {
}
// UNIX socket listener for hooks
- var hooksListener net.Listener
- var err error
- hooksListener, err = net.Listen("unix", config.Hooks.Socket)
- if errors.Is(err, syscall.EADDRINUSE) {
- clog.Warn("Removing existing socket " + config.Hooks.Socket)
- if err = syscall.Unlink(config.Hooks.Socket); err != nil {
- clog.Fatal(1, "Removing existing socket: "+err.Error())
- }
- if hooksListener, err = net.Listen("unix", config.Hooks.Socket); err != nil {
+ {
+ hooksListener, err := net.Listen("unix", config.Hooks.Socket)
+ if errors.Is(err, syscall.EADDRINUSE) {
+ clog.Warn("Removing existing socket " + config.Hooks.Socket)
+ if err = syscall.Unlink(config.Hooks.Socket); err != nil {
+ clog.Fatal(1, "Removing existing socket: "+err.Error())
+ }
+ if hooksListener, err = net.Listen("unix", config.Hooks.Socket); err != nil {
+ clog.Fatal(1, "Listening hooks: "+err.Error())
+ }
+ } else if err != nil {
clog.Fatal(1, "Listening hooks: "+err.Error())
}
- } else if err != nil {
- clog.Fatal(1, "Listening hooks: "+err.Error())
+ clog.Info("Listening hooks on unix " + config.Hooks.Socket)
+ go func() {
+ if err = serveGitHooks(hooksListener); err != nil {
+ clog.Fatal(1, "Serving hooks: "+err.Error())
+ }
+ }()
}
- clog.Info("Listening hooks on unix " + config.Hooks.Socket)
- go func() {
- if err = serveGitHooks(hooksListener); err != nil {
- clog.Fatal(1, "Serving hooks: "+err.Error())
+
+ // UNIX socket listener for LMTP
+ {
+ lmtpListener, err := net.Listen("unix", config.LMTP.Socket)
+ if errors.Is(err, syscall.EADDRINUSE) {
+ clog.Warn("Removing existing socket " + config.LMTP.Socket)
+ if err = syscall.Unlink(config.LMTP.Socket); err != nil {
+ clog.Fatal(1, "Removing existing socket: "+err.Error())
+ }
+ if lmtpListener, err = net.Listen("unix", config.LMTP.Socket); err != nil {
+ clog.Fatal(1, "Listening LMTP: "+err.Error())
+ }
+ } else if err != nil {
+ clog.Fatal(1, "Listening LMTP: "+err.Error())
}
- }()
+ clog.Info("Listening LMTP on unix " + config.LMTP.Socket)
+ go func() {
+ if err = serveLMTP(lmtpListener); err != nil {
+ clog.Fatal(1, "Serving LMTP: "+err.Error())
+ }
+ }()
+ }
// SSH listener
- sshListener, err := net.Listen(config.SSH.Net, config.SSH.Addr)
- if errors.Is(err, syscall.EADDRINUSE) && config.SSH.Net == "unix" {
- clog.Warn("Removing existing socket " + config.SSH.Addr)
- if err = syscall.Unlink(config.SSH.Addr); err != nil {
- clog.Fatal(1, "Removing existing socket: "+err.Error())
- }
- if sshListener, err = net.Listen(config.SSH.Net, config.SSH.Addr); err != nil {
+ {
+ sshListener, err := net.Listen(config.SSH.Net, config.SSH.Addr)
+ if errors.Is(err, syscall.EADDRINUSE) && config.SSH.Net == "unix" {
+ clog.Warn("Removing existing socket " + config.SSH.Addr)
+ if err = syscall.Unlink(config.SSH.Addr); err != nil {
+ clog.Fatal(1, "Removing existing socket: "+err.Error())
+ }
+ if sshListener, err = net.Listen(config.SSH.Net, config.SSH.Addr); err != nil {
+ clog.Fatal(1, "Listening SSH: "+err.Error())
+ }
+ } else if err != nil {
clog.Fatal(1, "Listening SSH: "+err.Error())
}
- } else if err != nil {
- clog.Fatal(1, "Listening SSH: "+err.Error())
+ clog.Info("Listening SSH on " + config.SSH.Net + " " + config.SSH.Addr)
+ go func() {
+ if err = serveSSH(sshListener); err != nil {
+ clog.Fatal(1, "Serving SSH: "+err.Error())
+ }
+ }()
}
- clog.Info("Listening SSH on " + config.SSH.Net + " " + config.SSH.Addr)
- go func() {
- if err = serveSSH(sshListener); err != nil {
- clog.Fatal(1, "Serving SSH: "+err.Error())
- }
- }()
// HTTP listener
- httpListener, err := net.Listen(config.HTTP.Net, config.HTTP.Addr)
- if errors.Is(err, syscall.EADDRINUSE) && config.HTTP.Net == "unix" {
- clog.Warn("Removing existing socket " + config.HTTP.Addr)
- if err = syscall.Unlink(config.HTTP.Addr); err != nil {
- clog.Fatal(1, "Removing existing socket: "+err.Error())
- }
- if httpListener, err = net.Listen(config.HTTP.Net, config.HTTP.Addr); err != nil {
+ {
+ httpListener, err := net.Listen(config.HTTP.Net, config.HTTP.Addr)
+ if errors.Is(err, syscall.EADDRINUSE) && config.HTTP.Net == "unix" {
+ clog.Warn("Removing existing socket " + config.HTTP.Addr)
+ if err = syscall.Unlink(config.HTTP.Addr); err != nil {
+ clog.Fatal(1, "Removing existing socket: "+err.Error())
+ }
+ if httpListener, err = net.Listen(config.HTTP.Net, config.HTTP.Addr); err != nil {
+ clog.Fatal(1, "Listening HTTP: "+err.Error())
+ }
+ } else if err != nil {
clog.Fatal(1, "Listening HTTP: "+err.Error())
}
- } else if err != nil {
- clog.Fatal(1, "Listening HTTP: "+err.Error())
+ server := http.Server{
+ Handler: &forgeHTTPRouter{},
+ ReadTimeout: time.Duration(config.HTTP.ReadTimeout) * time.Second,
+ WriteTimeout: time.Duration(config.HTTP.ReadTimeout) * time.Second,
+ IdleTimeout: time.Duration(config.HTTP.ReadTimeout) * time.Second,
+ } //exhaustruct:ignore
+ clog.Info("Listening HTTP on " + config.HTTP.Net + " " + config.HTTP.Addr)
+ go func() {
+ if err = server.Serve(httpListener); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ clog.Fatal(1, "Serving HTTP: "+err.Error())
+ }
+ }()
}
- server := http.Server{
- Handler: &forgeHTTPRouter{},
- ReadTimeout: time.Duration(config.HTTP.ReadTimeout) * time.Second,
- WriteTimeout: time.Duration(config.HTTP.ReadTimeout) * time.Second,
- IdleTimeout: time.Duration(config.HTTP.ReadTimeout) * time.Second,
- } //exhaustruct:ignore
- clog.Info("Listening HTTP on " + config.HTTP.Net + " " + config.HTTP.Addr)
- go func() {
- if err = server.Serve(httpListener); err != nil && !errors.Is(err, http.ErrServerClosed) {
- clog.Fatal(1, "Serving HTTP: "+err.Error())
- }
- }()
// IRC bot
go ircBotLoop()