diff options
author | tjpcc <tjp@ctrl-c.club> | 2023-01-28 14:52:35 -0700 |
---|---|---|
committer | tjpcc <tjp@ctrl-c.club> | 2023-01-28 15:01:41 -0700 |
commit | 66a1b1f39a1e1d5499b548b36d18c8daa872d7da (patch) | |
tree | 96471dbd5486ede1a908790ac23e0c55b226dfad /internal | |
parent | a27b879accb191b6a6c6e76a6251ed751967f73a (diff) |
gopher support.
Some of the contrib packages were originally built gemini-specific and
had to be refactored into generic core functionality and thin
protocol-specific wrappers for each of gemini and gopher.
Diffstat (limited to 'internal')
-rw-r--r-- | internal/server.go | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/internal/server.go b/internal/server.go new file mode 100644 index 0000000..38e478c --- /dev/null +++ b/internal/server.go @@ -0,0 +1,126 @@ +package internal + +import ( + "context" + "net" + "sync" + + "tildegit.org/tjp/gus/logging" +) + +type Server struct { + Ctx context.Context + Cancel context.CancelFunc + Wg *sync.WaitGroup + Listener net.Listener + HandleConn connHandler + ErrorLog logging.Logger + Host string + NetworkAddr net.Addr +} + +type connHandler func(net.Conn) + +func NewServer( + ctx context.Context, + hostname string, + network string, + address string, + errorLog logging.Logger, + handleConn connHandler, +) (Server, error) { + listener, err := net.Listen(network, address) + if err != nil { + return Server{}, err + } + + networkAddr := listener.Addr() + ctx, cancel := context.WithCancel(ctx) + + return Server{ + Ctx: ctx, + Cancel: cancel, + Wg: &sync.WaitGroup{}, + Listener: listener, + HandleConn: handleConn, + ErrorLog: errorLog, + Host: hostname, + NetworkAddr: networkAddr, + }, nil +} + +func (s *Server) Serve() error { + s.Wg.Add(1) + defer s.Wg.Done() + + s.propagateClose() + + for { + conn, err := s.Listener.Accept() + if err != nil { + if s.Closed() { + err = nil + } else { + _ = s.ErrorLog.Log("msg", "accept error", "error", err) + } + + return err + } + + s.Wg.Add(1) + go func() { + defer s.Wg.Done() + defer func() { + _ = conn.Close() + }() + + s.HandleConn(conn) + }() + } +} + +func (s *Server) Hostname() string { + host, _, _ := net.SplitHostPort(s.Host) + return host +} + +func (s *Server) Port() string { + _, port, _ := net.SplitHostPort(s.Host) + return port +} + +func (s *Server) Network() string { + return s.NetworkAddr.Network() +} + +func (s *Server) Address() string { + return s.NetworkAddr.String() +} + +func (s *Server) Close() { + s.Cancel() + s.Wg.Wait() +} + +func (s *Server) LogError(keyvals ...any) error { + return s.ErrorLog.Log(keyvals...) +} + +func (s *Server) Closed() bool { + select { + case <-s.Ctx.Done(): + return true + default: + return false + } +} + +func (s *Server) propagateClose() { + s.Wg.Add(1) + go func() { + defer s.Wg.Done() + + <-s.Ctx.Done() + _ = s.Listener.Close() + }() +} |