Files
sub2api-cn-relay-manager/internal/app/app.go
2026-05-12 22:44:30 +08:00

78 lines
1.4 KiB
Go

package app
import (
"context"
"errors"
"net"
"net/http"
"time"
)
type ListenerFactory func(network, address string) (net.Listener, error)
type Server struct {
server *http.Server
listen ListenerFactory
}
func NewServer(listenAddr string, listenerFactory ListenerFactory) *Server {
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok"))
})
server := &Server{
server: &http.Server{
Addr: listenAddr,
Handler: mux,
},
listen: net.Listen,
}
if listenerFactory != nil {
server.listen = listenerFactory
}
return server
}
func (s *Server) Addr() string {
return s.server.Addr
}
func (s *Server) Run(ctx context.Context) error {
listener, err := s.listen("tcp", s.server.Addr)
if err != nil {
return err
}
return s.Serve(ctx, listener)
}
func (s *Server) Serve(ctx context.Context, listener net.Listener) error {
errCh := make(chan error, 1)
go func() {
err := s.server.Serve(listener)
if errors.Is(err, http.ErrServerClosed) {
err = nil
}
errCh <- err
}()
select {
case <-ctx.Done():
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := s.server.Shutdown(shutdownCtx); err != nil {
return err
}
return <-errCh
case err := <-errCh:
return err
}
}