diff --git a/cmd/soft/serve/server.go b/cmd/soft/serve/server.go index 33679091f..69d5db5a8 100644 --- a/cmd/soft/serve/server.go +++ b/cmd/soft/serve/server.go @@ -95,7 +95,7 @@ func (s *Server) Start() error { errg, _ := errgroup.WithContext(s.ctx) errg.Go(func() error { s.logger.Print("Starting Git daemon", "addr", s.Config.Git.ListenAddr) - if err := s.GitDaemon.Start(); !errors.Is(err, daemon.ErrServerClosed) { + if err := s.GitDaemon.ListenAndServe(); !errors.Is(err, daemon.ErrServerClosed) { return err } return nil diff --git a/pkg/daemon/daemon.go b/pkg/daemon/daemon.go index 9eaa7661e..104499017 100644 --- a/pkg/daemon/daemon.go +++ b/pkg/daemon/daemon.go @@ -43,7 +43,6 @@ var ErrServerClosed = fmt.Errorf("git: %w", net.ErrClosed) // GitDaemon represents a Git daemon. type GitDaemon struct { ctx context.Context - listener net.Listener addr string finished chan struct{} conns connections @@ -52,6 +51,7 @@ type GitDaemon struct { wg sync.WaitGroup once sync.Once logger *log.Logger + done bool // indicates if the server has been closed } // NewDaemon returns a new Git daemon. @@ -70,26 +70,31 @@ func NewGitDaemon(ctx context.Context) (*GitDaemon, error) { return d, nil } -// Start starts the Git TCP daemon. -func (d *GitDaemon) Start() error { - // listen on the socket - { - listener, err := net.Listen("tcp", d.addr) - if err != nil { - return err - } - d.listener = listener +// ListenAndServe starts the Git TCP daemon. +func (d *GitDaemon) ListenAndServe() error { + if d.done { + return ErrServerClosed + } + listener, err := net.Listen("tcp", d.addr) + if err != nil { + return err } + return d.Serve(listener) +} - // close eventual connections to the socket - defer d.listener.Close() // nolint: errcheck +// Serve listens on the TCP network address and serves Git requests. +func (d *GitDaemon) Serve(listener net.Listener) error { + if d.done { + return ErrServerClosed + } d.wg.Add(1) defer d.wg.Done() + defer listener.Close() //nolint:errcheck var tempDelay time.Duration for { - conn, err := d.listener.Accept() + conn, err := listener.Accept() if err != nil { select { case <-d.finished: @@ -311,19 +316,21 @@ func (d *GitDaemon) Close() error { } // closeListener closes the listener and the finished channel. -func (d *GitDaemon) closeListener() (err error) { +func (d *GitDaemon) closeListener() error { + if d.done { + return ErrServerClosed + } d.once.Do(func() { close(d.finished) - err = d.listener.Close() + d.done = true }) - return + return nil } // Shutdown gracefully shuts down the daemon. func (d *GitDaemon) Shutdown(ctx context.Context) error { - // in the case when git daemon was never started - if d.listener == nil { - return nil + if d.done { + return ErrServerClosed } err := d.closeListener() diff --git a/pkg/daemon/daemon_test.go b/pkg/daemon/daemon_test.go index 88b4fdec7..f67dad17e 100644 --- a/pkg/daemon/daemon_test.go +++ b/pkg/daemon/daemon_test.go @@ -59,7 +59,7 @@ func TestMain(m *testing.M) { } testDaemon = d go func() { - if err := d.Start(); err != ErrServerClosed { + if err := d.ListenAndServe(); err != ErrServerClosed { log.Fatal(err) } }()