aboutsummaryrefslogtreecommitdiff
path: root/forged/internal/incoming/lmtp/lmtp.go
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-08-17 13:31:41 +0800
committerRunxi Yu <me@runxiyu.org>2025-08-17 13:36:51 +0800
commita7bd17c605e79446d8bf02e474c91986c615b36a (patch)
tree6d9b610c259c92eadda56ecf20943670ae426224 /forged/internal/incoming/lmtp/lmtp.go
parentTidying (diff)
downloadforge-a7bd17c605e79446d8bf02e474c91986c615b36a.tar.gz
forge-a7bd17c605e79446d8bf02e474c91986c615b36a.tar.zst
forge-a7bd17c605e79446d8bf02e474c91986c615b36a.zip
Linting
Diffstat (limited to 'forged/internal/incoming/lmtp/lmtp.go')
-rw-r--r--forged/internal/incoming/lmtp/lmtp.go75
1 files changed, 75 insertions, 0 deletions
diff --git a/forged/internal/incoming/lmtp/lmtp.go b/forged/internal/incoming/lmtp/lmtp.go
new file mode 100644
index 0000000..cf5618c
--- /dev/null
+++ b/forged/internal/incoming/lmtp/lmtp.go
@@ -0,0 +1,75 @@
+package lmtp
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "time"
+
+ "go.lindenii.runxiyu.org/forge/forged/internal/common/misc"
+)
+
+type Server struct {
+ socket string
+ domain string
+ maxSize int64
+ writeTimeout uint32
+ readTimeout uint32
+}
+
+type Config struct {
+ Socket string `scfg:"socket"`
+ Domain string `scfg:"domain"`
+ MaxSize int64 `scfg:"max_size"`
+ WriteTimeout uint32 `scfg:"write_timeout"`
+ ReadTimeout uint32 `scfg:"read_timeout"`
+}
+
+func New(config Config) (server *Server) {
+ return &Server{
+ socket: config.Socket,
+ domain: config.Domain,
+ maxSize: config.MaxSize,
+ writeTimeout: config.WriteTimeout,
+ readTimeout: config.ReadTimeout,
+ }
+}
+
+func (server *Server) Run(ctx context.Context) error {
+ listener, _, err := misc.ListenUnixSocket(server.socket)
+ if err != nil {
+ return fmt.Errorf("listen unix socket for LMTP: %w", err)
+ }
+ defer func() {
+ _ = listener.Close()
+ }()
+
+ stop := context.AfterFunc(ctx, func() {
+ _ = listener.Close()
+ })
+ defer stop()
+
+ for {
+ conn, err := listener.Accept()
+ if err != nil {
+ if errors.Is(err, net.ErrClosed) || ctx.Err() != nil {
+ return nil
+ }
+ return fmt.Errorf("accept conn: %w", err)
+ }
+
+ go server.handleConn(ctx, conn)
+ }
+}
+
+func (server *Server) handleConn(ctx context.Context, conn net.Conn) {
+ defer func() {
+ _ = conn.Close()
+ }()
+ unblock := context.AfterFunc(ctx, func() {
+ _ = conn.SetDeadline(time.Now())
+ _ = conn.Close()
+ })
+ defer unblock()
+}