Add an `Unwrap` to the `Listener`

To obtain a reference to the underlying [*net.TCPListener]
of a [net.Listener] the [UnwrappableListener] interface was
added.
pull/1659/head
Herman Slatman 5 months ago
parent 82e0984018
commit 1d096cbcd4
No known key found for this signature in database
GPG Key ID: F4D8A44EA0A75A4F

@ -65,17 +65,25 @@ func (srv *Server) ListenAndServe() error {
// Serve runs Serve or ServeTLS on the underlying http.Server and listen to // Serve runs Serve or ServeTLS on the underlying http.Server and listen to
// channels to reload or shutdown the server. // channels to reload or shutdown the server.
func (srv *Server) Serve(ln net.Listener) error { func (srv *Server) Serve(ln net.Listener) error {
var err error var (
listener = ln
err error
)
// Attempt to unwrap the listener if it's a [Listener].
wl, isWrapped := listener.(*Listener)
if isWrapped {
listener = wl.listener.Unwrap()
}
switch l := ln.(type) { // Store the current listener. When the server is reloaded a copy of the
case *net.TCPListener: // underlying os.File is created, so when the server is closed, it does
// Store the current listener. // not affect the copy.
// In reloads we'll create a copy of the underlying os.File so the close of the server one does not affect the copy. if ll, ok := listener.(*net.TCPListener); ok {
srv.listener = l srv.listener = ll
} }
for { for {
wl, isWrapped := ln.(*WrappedListener)
switch { switch {
case srv.TLSConfig == nil || (len(srv.TLSConfig.Certificates) == 0 && srv.TLSConfig.GetCertificate == nil): case srv.TLSConfig == nil || (len(srv.TLSConfig.Certificates) == 0 && srv.TLSConfig.GetCertificate == nil):
log.Printf("Serving HTTP on %s ...", srv.Addr) log.Printf("Serving HTTP on %s ...", srv.Addr)
@ -102,34 +110,43 @@ func (srv *Server) Serve(ln net.Listener) error {
} }
} }
// NewWrappedListener wraps the inner [net.Listener]. // UnwrappableListener indicates a [net.Listener] that can
func NewWrappedListener(inner net.Listener, proto string) *WrappedListener { // be unwrapped to obtain the underlying [net.Listener]. It
return &WrappedListener{ // is used by the [Server] to obtain a [*net.TCPListener]
inner: inner, // implementing the [net.Listener] interface.
proto: strings.ToUpper(proto), type UnwrappableListener interface {
net.Listener
Unwrap() net.Listener
}
// NewListener wraps the inner [net.Listener].
func NewListener(listener UnwrappableListener, proto string) *Listener {
return &Listener{
listener: listener,
proto: strings.ToUpper(proto),
} }
} }
// WrappedListener wraps a [net.Listener]. // Listener wraps a [net.Listener].
type WrappedListener struct { type Listener struct {
inner net.Listener listener UnwrappableListener
proto string proto string
} }
// Accept waits for and returns the next connection to the listener. // Accept waits for and returns the next connection to the listener.
func (w *WrappedListener) Accept() (net.Conn, error) { func (w *Listener) Accept() (net.Conn, error) {
return w.inner.Accept() return w.listener.Accept()
} }
// Close closes the listener. // Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors. // Any blocked Accept operations will be unblocked and return errors.
func (w *WrappedListener) Close() error { func (w *Listener) Close() error {
return w.inner.Close() return w.listener.Close()
} }
// Addr returns the listener's network address. // Addr returns the listener's network address.
func (w *WrappedListener) Addr() net.Addr { func (w *Listener) Addr() net.Addr {
return w.inner.Addr() return w.listener.Addr()
} }
// Shutdown gracefully shuts down the server without interrupting any active // Shutdown gracefully shuts down the server without interrupting any active

Loading…
Cancel
Save